From 8998d0e3a4a0a8e7010d2d758a69e420f47f29af Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 18 Mar 2022 18:14:35 +0100 Subject: [PATCH 001/180] [core] Make Report mutable Refs #3792 This changes the getters to return mutable list. This allows any downstream consumers of the Report to make modifications to it before passing it manually to a renderer. --- .../main/java/net/sourceforge/pmd/Report.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/Report.java b/pmd-core/src/main/java/net/sourceforge/pmd/Report.java index cd4c3c5b96..799c763533 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/Report.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/Report.java @@ -548,38 +548,38 @@ public class Report implements Iterable { /** - * Returns an unmodifiable list of violations that were suppressed. + * Returns a list of violations that were suppressed. */ public final List getSuppressedViolations() { - return Collections.unmodifiableList(suppressedRuleViolations); + return suppressedRuleViolations; } /** - * Returns an unmodifiable list of violations that have been + * Returns a list of violations that have been * recorded until now. None of those violations were suppressed. * *

The violations list is sorted with {@link RuleViolation#DEFAULT_COMPARATOR}. */ public final List getViolations() { - return Collections.unmodifiableList(violations); + return violations; } /** - * Returns an unmodifiable list of processing errors that have been + * Returns a list of processing errors that have been * recorded until now. */ public final List getProcessingErrors() { - return Collections.unmodifiableList(errors); + return errors; } /** - * Returns an unmodifiable list of configuration errors that have + * Returns a list of configuration errors that have * been recorded until now. */ public final List getConfigurationErrors() { - return Collections.unmodifiableList(configErrors); + return configErrors; } From cd7e3a3e0d28b209b858a3a6ca3c444de784e811 Mon Sep 17 00:00:00 2001 From: jeickhoff Date: Mon, 21 Mar 2022 11:32:12 +0100 Subject: [PATCH 002/180] Implement CLI progress bar using me.tongfei.progressbar --- pmd-core/pom.xml | 5 + .../net/sourceforge/pmd/PMDConfiguration.java | 22 +++++ .../java/net/sourceforge/pmd/PmdAnalysis.java | 10 +- .../sourceforge/pmd/cli/PMDParameters.java | 9 ++ .../pmd/reporting/ProgressBarListener.java | 91 +++++++++++++++++++ 5 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 pmd-core/src/main/java/net/sourceforge/pmd/reporting/ProgressBarListener.java diff --git a/pmd-core/pom.xml b/pmd-core/pom.xml index c4d35c5be9..b96f988a88 100644 --- a/pmd-core/pom.xml +++ b/pmd-core/pom.xml @@ -162,5 +162,10 @@ system-rules test + + me.tongfei + progressbar + 0.9.3 + diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/PMDConfiguration.java b/pmd-core/src/main/java/net/sourceforge/pmd/PMDConfiguration.java index bc6e618aa2..aac28d62c7 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/PMDConfiguration.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/PMDConfiguration.java @@ -122,6 +122,7 @@ public class PMDConfiguration extends AbstractConfiguration { private boolean benchmark; private AnalysisCache analysisCache = new NoopAnalysisCache(); private boolean ignoreIncrementalAnalysis; + private boolean progressBar; /** * Get the suppress marker. This is the source level marker used to indicate @@ -780,4 +781,25 @@ public class PMDConfiguration extends AbstractConfiguration { public boolean isIgnoreIncrementalAnalysis() { return ignoreIncrementalAnalysis; } + + /** + * Sets whether to indicate analysis progress in command line output. + * + * @param progressBar Whether to enable progress bar indicator in CLI + */ + public void setProgressBar(boolean progressBar) { + this.progressBar = progressBar; + } + + + /** + * Returns whether progress bar indicator should be used. + * + * @return {@code true} if progress bar indicator is enabled + */ + public boolean isProgressBar() { + return progressBar; + } + + } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/PmdAnalysis.java b/pmd-core/src/main/java/net/sourceforge/pmd/PmdAnalysis.java index 1b74fa5ab8..d3acbc6ca6 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/PmdAnalysis.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/PmdAnalysis.java @@ -32,6 +32,7 @@ import net.sourceforge.pmd.lang.document.FileCollector; import net.sourceforge.pmd.processor.AbstractPMDProcessor; import net.sourceforge.pmd.renderers.Renderer; import net.sourceforge.pmd.reporting.GlobalAnalysisListener; +import net.sourceforge.pmd.reporting.ProgressBarListener; import net.sourceforge.pmd.util.ClasspathClassLoader; import net.sourceforge.pmd.util.IOUtil; import net.sourceforge.pmd.util.datasource.DataSource; @@ -287,7 +288,14 @@ public final class PmdAnalysis implements AutoCloseable { GlobalAnalysisListener listener; try { @SuppressWarnings("PMD.CloseResource") AnalysisCacheListener cacheListener = new AnalysisCacheListener(configuration.getAnalysisCache(), rulesets, configuration.getClassLoader()); - listener = GlobalAnalysisListener.tee(listOf(createComposedRendererListener(renderers), GlobalAnalysisListener.tee(listeners), GlobalAnalysisListener.tee(extraListeners), cacheListener)); + if (configuration.isProgressBar()) { + @SuppressWarnings("PMD.CloseResource") ProgressBarListener progressBarListener = new ProgressBarListener(dataSources.size()); + addListener(progressBarListener); + } + listener = GlobalAnalysisListener.tee(listOf(createComposedRendererListener(renderers), + GlobalAnalysisListener.tee(listeners), + GlobalAnalysisListener.tee(extraListeners), + cacheListener)); } catch (Exception e) { reporter.errorEx("Exception while initializing analysis listeners", e); throw new RuntimeException("Exception while initializing analysis listeners", e); diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cli/PMDParameters.java b/pmd-core/src/main/java/net/sourceforge/pmd/cli/PMDParameters.java index 7cea583a26..299d936a03 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/cli/PMDParameters.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/cli/PMDParameters.java @@ -136,6 +136,9 @@ public class PMDParameters { @Parameter(names = { "--no-cache", "-no-cache" }, description = "Explicitly disable incremental analysis. The '-cache' option is ignored if this switch is present in the command line.") private boolean noCache = false; + @Parameter(names = { "--progress-bar", "-progress" }, description = "Enables progress bar indicator of live analysis progress.") + private boolean progressBar = false; + // this has to be a public static class, so that JCommander can use it! public static class PropertyConverter implements IStringConverter { @@ -222,6 +225,7 @@ public class PMDParameters { configuration.setFailOnViolation(this.isFailOnViolation()); configuration.setAnalysisCacheLocation(this.cacheLocation); configuration.setIgnoreIncrementalAnalysis(this.isIgnoreIncrementalAnalysis()); + configuration.setProgressBar(this.isProgressBar()); LanguageVersion forceLangVersion = getForceLangVersion(); if (forceLangVersion != null) { @@ -368,6 +372,11 @@ public class PMDParameters { return failOnViolation; } + public boolean isProgressBar() { + return progressBar; + } + + /** * @return the uri alternative to source directory. */ diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/reporting/ProgressBarListener.java b/pmd-core/src/main/java/net/sourceforge/pmd/reporting/ProgressBarListener.java new file mode 100644 index 0000000000..a42d8a2518 --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/reporting/ProgressBarListener.java @@ -0,0 +1,91 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.reporting; + +import net.sourceforge.pmd.Report; +import net.sourceforge.pmd.RuleViolation; +import net.sourceforge.pmd.util.datasource.DataSource; + +import me.tongfei.progressbar.ProgressBar; +import me.tongfei.progressbar.ProgressBarBuilder; +import me.tongfei.progressbar.ProgressBarStyle; + +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Collects runtime analysis statistics and displays them live on command line output. + * Toggled through -progress command line argument. + */ +public final class ProgressBarListener implements GlobalAnalysisListener { + private final ProgressBar progressBar; + private final AtomicInteger numErrors = new AtomicInteger(0); + private final AtomicInteger numViolations = new AtomicInteger(0); + + public ProgressBarListener(int totalFiles) { + progressBar = new ProgressBarBuilder() + .setInitialMax(totalFiles) + .setStyle(ProgressBarStyle.ASCII) + .continuousUpdate() + .build(); + progressBar.setExtraMessage(extraMessage() + "\r"); + } + + private void incrementProgress(){ + progressBar.step(); + refreshProgressBar(); + } + + /** + * Updates progress bar string and forces it to be output regardless of its update interval. + */ + private void refreshProgressBar(){ + // Use trailing carriage return to interleave with other output + if(progressBar.getCurrent() != progressBar.getMax()){ + progressBar.setExtraMessage(extraMessage() + "\r"); + } else { + // Don't include trailing carriage return on last draw + progressBar.setExtraMessage(extraMessage() + System.lineSeparator()); + } + progressBar.refresh(); + } + + private String extraMessage(){ + return String.format("Violations:%d, Errors:%d", numViolations.get(), numErrors.get()); + } + + @Override + public FileAnalysisListener startFileAnalysis(DataSource file) { + // Refresh progress on file analysis start + ProgressBarListener.this.refreshProgressBar(); + + return new FileAnalysisListener() { + @Override + public void onRuleViolation(RuleViolation violation) { + ProgressBarListener.this.numViolations.addAndGet(1); + } + + @Override + public void onSuppressedRuleViolation(Report.SuppressedViolation violation) { + /*Not handled*/ + } + + @Override + public void onError(Report.ProcessingError error) { + ProgressBarListener.this.numErrors.addAndGet(1); + } + + @Override + public void close() { + // Refresh progress bar on file analysis end (or file was in cache) + ProgressBarListener.this.incrementProgress(); + } + }; + } + + @Override + public void close() throws Exception { + /*ProgressBar auto-closed*/ + } +} From 3338b5e6ba34af50cc3e1bfc62de9f5d088539d5 Mon Sep 17 00:00:00 2001 From: jeickhoff Date: Mon, 21 Mar 2022 12:49:46 +0100 Subject: [PATCH 003/180] Small style fixes --- .../pmd/reporting/ProgressBarListener.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/reporting/ProgressBarListener.java b/pmd-core/src/main/java/net/sourceforge/pmd/reporting/ProgressBarListener.java index a42d8a2518..a490ea81ac 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/reporting/ProgressBarListener.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/reporting/ProgressBarListener.java @@ -4,16 +4,17 @@ package net.sourceforge.pmd.reporting; +import java.util.concurrent.atomic.AtomicInteger; + import net.sourceforge.pmd.Report; import net.sourceforge.pmd.RuleViolation; import net.sourceforge.pmd.util.datasource.DataSource; +import me.tongfei.progressbar.DelegatingProgressBarConsumer; import me.tongfei.progressbar.ProgressBar; import me.tongfei.progressbar.ProgressBarBuilder; import me.tongfei.progressbar.ProgressBarStyle; -import java.util.concurrent.atomic.AtomicInteger; - /** * Collects runtime analysis statistics and displays them live on command line output. * Toggled through -progress command line argument. @@ -28,11 +29,12 @@ public final class ProgressBarListener implements GlobalAnalysisListener { .setInitialMax(totalFiles) .setStyle(ProgressBarStyle.ASCII) .continuousUpdate() + .setConsumer(new DelegatingProgressBarConsumer(System.out::print)) .build(); progressBar.setExtraMessage(extraMessage() + "\r"); } - private void incrementProgress(){ + private void incrementProgress() { progressBar.step(); refreshProgressBar(); } @@ -40,9 +42,9 @@ public final class ProgressBarListener implements GlobalAnalysisListener { /** * Updates progress bar string and forces it to be output regardless of its update interval. */ - private void refreshProgressBar(){ + private void refreshProgressBar() { // Use trailing carriage return to interleave with other output - if(progressBar.getCurrent() != progressBar.getMax()){ + if (progressBar.getCurrent() != progressBar.getMax()) { progressBar.setExtraMessage(extraMessage() + "\r"); } else { // Don't include trailing carriage return on last draw @@ -51,14 +53,14 @@ public final class ProgressBarListener implements GlobalAnalysisListener { progressBar.refresh(); } - private String extraMessage(){ + private String extraMessage() { return String.format("Violations:%d, Errors:%d", numViolations.get(), numErrors.get()); } @Override public FileAnalysisListener startFileAnalysis(DataSource file) { // Refresh progress on file analysis start - ProgressBarListener.this.refreshProgressBar(); + refreshProgressBar(); return new FileAnalysisListener() { @Override From 997fef92d0c637cdfad4bbd0640ba1ab1441e485 Mon Sep 17 00:00:00 2001 From: jeickhoff Date: Mon, 21 Mar 2022 13:13:21 +0100 Subject: [PATCH 004/180] Progress bar output choice --- .../src/main/java/net/sourceforge/pmd/PmdAnalysis.java | 2 +- .../net/sourceforge/pmd/reporting/ProgressBarListener.java | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/PmdAnalysis.java b/pmd-core/src/main/java/net/sourceforge/pmd/PmdAnalysis.java index d3acbc6ca6..bcc4c0ab30 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/PmdAnalysis.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/PmdAnalysis.java @@ -289,7 +289,7 @@ public final class PmdAnalysis implements AutoCloseable { try { @SuppressWarnings("PMD.CloseResource") AnalysisCacheListener cacheListener = new AnalysisCacheListener(configuration.getAnalysisCache(), rulesets, configuration.getClassLoader()); if (configuration.isProgressBar()) { - @SuppressWarnings("PMD.CloseResource") ProgressBarListener progressBarListener = new ProgressBarListener(dataSources.size()); + @SuppressWarnings("PMD.CloseResource") ProgressBarListener progressBarListener = new ProgressBarListener(dataSources.size(), System.out::print); addListener(progressBarListener); } listener = GlobalAnalysisListener.tee(listOf(createComposedRendererListener(renderers), diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/reporting/ProgressBarListener.java b/pmd-core/src/main/java/net/sourceforge/pmd/reporting/ProgressBarListener.java index a490ea81ac..09659c1740 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/reporting/ProgressBarListener.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/reporting/ProgressBarListener.java @@ -5,6 +5,7 @@ package net.sourceforge.pmd.reporting; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; import net.sourceforge.pmd.Report; import net.sourceforge.pmd.RuleViolation; @@ -23,13 +24,13 @@ public final class ProgressBarListener implements GlobalAnalysisListener { private final ProgressBar progressBar; private final AtomicInteger numErrors = new AtomicInteger(0); private final AtomicInteger numViolations = new AtomicInteger(0); - - public ProgressBarListener(int totalFiles) { + + public ProgressBarListener(int totalFiles, Consumer loggingFunction) { progressBar = new ProgressBarBuilder() .setInitialMax(totalFiles) .setStyle(ProgressBarStyle.ASCII) .continuousUpdate() - .setConsumer(new DelegatingProgressBarConsumer(System.out::print)) + .setConsumer(new DelegatingProgressBarConsumer(loggingFunction)) .build(); progressBar.setExtraMessage(extraMessage() + "\r"); } From f5c21828c81d62dd700bc8fbd3993b15cfccfc2e Mon Sep 17 00:00:00 2001 From: jeickhoff Date: Fri, 25 Mar 2022 14:43:53 +0100 Subject: [PATCH 005/180] Move ProgressBarListener to cli.internal package --- pmd-core/src/main/java/net/sourceforge/pmd/PmdAnalysis.java | 2 +- .../pmd/{reporting => cli/internal}/ProgressBarListener.java | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) rename pmd-core/src/main/java/net/sourceforge/pmd/{reporting => cli/internal}/ProgressBarListener.java (95%) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/PmdAnalysis.java b/pmd-core/src/main/java/net/sourceforge/pmd/PmdAnalysis.java index bcc4c0ab30..bbd5438adf 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/PmdAnalysis.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/PmdAnalysis.java @@ -32,7 +32,7 @@ import net.sourceforge.pmd.lang.document.FileCollector; import net.sourceforge.pmd.processor.AbstractPMDProcessor; import net.sourceforge.pmd.renderers.Renderer; import net.sourceforge.pmd.reporting.GlobalAnalysisListener; -import net.sourceforge.pmd.reporting.ProgressBarListener; +import net.sourceforge.pmd.cli.internal.ProgressBarListener; import net.sourceforge.pmd.util.ClasspathClassLoader; import net.sourceforge.pmd.util.IOUtil; import net.sourceforge.pmd.util.datasource.DataSource; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/reporting/ProgressBarListener.java b/pmd-core/src/main/java/net/sourceforge/pmd/cli/internal/ProgressBarListener.java similarity index 95% rename from pmd-core/src/main/java/net/sourceforge/pmd/reporting/ProgressBarListener.java rename to pmd-core/src/main/java/net/sourceforge/pmd/cli/internal/ProgressBarListener.java index 09659c1740..c0fe808a4b 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/reporting/ProgressBarListener.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/cli/internal/ProgressBarListener.java @@ -2,13 +2,15 @@ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -package net.sourceforge.pmd.reporting; +package net.sourceforge.pmd.cli.internal; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; import net.sourceforge.pmd.Report; import net.sourceforge.pmd.RuleViolation; +import net.sourceforge.pmd.reporting.FileAnalysisListener; +import net.sourceforge.pmd.reporting.GlobalAnalysisListener; import net.sourceforge.pmd.util.datasource.DataSource; import me.tongfei.progressbar.DelegatingProgressBarConsumer; From 15674891c234fd299961e8d36baec5c1672c94a4 Mon Sep 17 00:00:00 2001 From: jeickhoff Date: Fri, 25 Mar 2022 14:46:34 +0100 Subject: [PATCH 006/180] Switch progress bar default to activated --- .../src/main/java/net/sourceforge/pmd/cli/PMDParameters.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cli/PMDParameters.java b/pmd-core/src/main/java/net/sourceforge/pmd/cli/PMDParameters.java index 299d936a03..10236022f7 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/cli/PMDParameters.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/cli/PMDParameters.java @@ -136,8 +136,8 @@ public class PMDParameters { @Parameter(names = { "--no-cache", "-no-cache" }, description = "Explicitly disable incremental analysis. The '-cache' option is ignored if this switch is present in the command line.") private boolean noCache = false; - @Parameter(names = { "--progress-bar", "-progress" }, description = "Enables progress bar indicator of live analysis progress.") - private boolean progressBar = false; + @Parameter(names = { "--no-progress" }, description = "Disables progress bar indicator of live analysis progress.") + private boolean progressBar = true; // this has to be a public static class, so that JCommander can use it! public static class PropertyConverter implements IStringConverter { From 9241da3bf8d0f3c580bf4be5d89e7b0006f4231f Mon Sep 17 00:00:00 2001 From: jeickhoff Date: Fri, 25 Mar 2022 14:54:21 +0100 Subject: [PATCH 007/180] Add progress bar task name --- .../net/sourceforge/pmd/cli/internal/ProgressBarListener.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cli/internal/ProgressBarListener.java b/pmd-core/src/main/java/net/sourceforge/pmd/cli/internal/ProgressBarListener.java index c0fe808a4b..8c27669e79 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/cli/internal/ProgressBarListener.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/cli/internal/ProgressBarListener.java @@ -20,7 +20,7 @@ import me.tongfei.progressbar.ProgressBarStyle; /** * Collects runtime analysis statistics and displays them live on command line output. - * Toggled through -progress command line argument. + * Toggled off through --no-progress command line argument. */ public final class ProgressBarListener implements GlobalAnalysisListener { private final ProgressBar progressBar; @@ -29,6 +29,7 @@ public final class ProgressBarListener implements GlobalAnalysisListener { public ProgressBarListener(int totalFiles, Consumer loggingFunction) { progressBar = new ProgressBarBuilder() + .setTaskName("Processing") .setInitialMax(totalFiles) .setStyle(ProgressBarStyle.ASCII) .continuousUpdate() From 9ca8176d3e197ffbe28a6eced1820c3616cd2954 Mon Sep 17 00:00:00 2001 From: jeickhoff Date: Fri, 25 Mar 2022 16:35:49 +0100 Subject: [PATCH 008/180] Fix pmd-test with progress bar flag --- pmd-core/src/main/java/net/sourceforge/pmd/PmdAnalysis.java | 2 +- .../main/java/net/sourceforge/pmd/cli/PMDParameters.java | 6 +++--- .../src/test/java/net/sourceforge/pmd/it/PMDExecutor.java | 5 +++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/PmdAnalysis.java b/pmd-core/src/main/java/net/sourceforge/pmd/PmdAnalysis.java index bbd5438adf..4d6d74ebc8 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/PmdAnalysis.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/PmdAnalysis.java @@ -23,6 +23,7 @@ import net.sourceforge.pmd.benchmark.TimeTracker; import net.sourceforge.pmd.benchmark.TimedOperation; import net.sourceforge.pmd.benchmark.TimedOperationCategory; import net.sourceforge.pmd.cache.AnalysisCacheListener; +import net.sourceforge.pmd.cli.internal.ProgressBarListener; import net.sourceforge.pmd.internal.util.AssertionUtil; import net.sourceforge.pmd.internal.util.FileCollectionUtil; import net.sourceforge.pmd.lang.Language; @@ -32,7 +33,6 @@ import net.sourceforge.pmd.lang.document.FileCollector; import net.sourceforge.pmd.processor.AbstractPMDProcessor; import net.sourceforge.pmd.renderers.Renderer; import net.sourceforge.pmd.reporting.GlobalAnalysisListener; -import net.sourceforge.pmd.cli.internal.ProgressBarListener; import net.sourceforge.pmd.util.ClasspathClassLoader; import net.sourceforge.pmd.util.IOUtil; import net.sourceforge.pmd.util.datasource.DataSource; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cli/PMDParameters.java b/pmd-core/src/main/java/net/sourceforge/pmd/cli/PMDParameters.java index 10236022f7..df10f008f7 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/cli/PMDParameters.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/cli/PMDParameters.java @@ -136,8 +136,8 @@ public class PMDParameters { @Parameter(names = { "--no-cache", "-no-cache" }, description = "Explicitly disable incremental analysis. The '-cache' option is ignored if this switch is present in the command line.") private boolean noCache = false; - @Parameter(names = { "--no-progress" }, description = "Disables progress bar indicator of live analysis progress.") - private boolean progressBar = true; + @Parameter(names = { "--no-progress", "-no-progress" }, description = "Disables progress bar indicator of live analysis progress.") + private boolean noProgressBar = false; // this has to be a public static class, so that JCommander can use it! public static class PropertyConverter implements IStringConverter { @@ -373,7 +373,7 @@ public class PMDParameters { } public boolean isProgressBar() { - return progressBar; + return !noProgressBar; } diff --git a/pmd-dist/src/test/java/net/sourceforge/pmd/it/PMDExecutor.java b/pmd-dist/src/test/java/net/sourceforge/pmd/it/PMDExecutor.java index 673ff76138..1ab6ddbba2 100644 --- a/pmd-dist/src/test/java/net/sourceforge/pmd/it/PMDExecutor.java +++ b/pmd-dist/src/test/java/net/sourceforge/pmd/it/PMDExecutor.java @@ -28,6 +28,7 @@ public class PMDExecutor { private static final String FORMAT_FLAG = "-f"; private static final String FORMATTER = "text"; private static final String REPORTFILE_FLAG = "-r"; + private static final String NO_PROGRESSBAR_FLAG = "--no-progress"; private PMDExecutor() { // this is a helper class only @@ -108,10 +109,10 @@ public class PMDExecutor { public static ExecutionResult runPMDRules(Path reportFile, Path tempDir, String sourceDirectory, String ruleset, String formatter) throws Exception { if (SystemUtils.IS_OS_WINDOWS) { return runPMDWindows(tempDir, reportFile, SOURCE_DIRECTORY_FLAG, sourceDirectory, RULESET_FLAG, ruleset, - FORMAT_FLAG, formatter, REPORTFILE_FLAG, reportFile.toAbsolutePath().toString()); + FORMAT_FLAG, formatter, REPORTFILE_FLAG, reportFile.toAbsolutePath().toString(), NO_PROGRESSBAR_FLAG); } else { return runPMDUnix(tempDir, reportFile, SOURCE_DIRECTORY_FLAG, sourceDirectory, RULESET_FLAG, ruleset, - FORMAT_FLAG, formatter, REPORTFILE_FLAG, reportFile.toAbsolutePath().toString()); + FORMAT_FLAG, formatter, REPORTFILE_FLAG, reportFile.toAbsolutePath().toString(), NO_PROGRESSBAR_FLAG); } } From 4a12aebbf9f4c15d3c1be41c06ae4372cf4749ad Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sun, 27 Mar 2022 17:48:08 +0200 Subject: [PATCH 009/180] Bump pmd from 6.43.0 to 6.44.0 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 42669441d9..94ed6846fd 100644 --- a/pom.xml +++ b/pom.xml @@ -406,12 +406,12 @@ net.sourceforge.pmd pmd-core - 6.43.0 + 6.44.0 net.sourceforge.pmd pmd-java - 6.43.0 + 6.44.0 From 2a57871fdbdf4382592612c1a5adac5bb26ac40f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Mar 2022 03:01:58 +0000 Subject: [PATCH 010/180] Bump actions/cache from 2 to 3 Bumps [actions/cache](https://github.com/actions/cache) from 2 to 3. - [Release notes](https://github.com/actions/cache/releases) - [Commits](https://github.com/actions/cache/compare/v2...v3) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/build.yml | 2 +- .github/workflows/troubleshooting.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 566fc4f2fd..6dadb3e2d8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -25,7 +25,7 @@ jobs: - uses: actions/checkout@v3 with: fetch-depth: 2 - - uses: actions/cache@v2 + - uses: actions/cache@v3 with: path: | ~/.m2/repository diff --git a/.github/workflows/troubleshooting.yml b/.github/workflows/troubleshooting.yml index dc8f796c12..31a90eef7f 100644 --- a/.github/workflows/troubleshooting.yml +++ b/.github/workflows/troubleshooting.yml @@ -13,7 +13,7 @@ jobs: steps: - uses: actions/checkout@v3 - - uses: actions/cache@v2 + - uses: actions/cache@v3 with: path: | ~/.m2/repository From d662e9f8efe219a868a079687f3b01d594cda77a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 30 Mar 2022 21:59:39 +0200 Subject: [PATCH 011/180] Fix AssertionError (exhaustive switch) Ref #3881 --- .../net/sourceforge/pmd/util/log/MessageReporter.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/log/MessageReporter.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/log/MessageReporter.java index b6843d68de..ecf9fb5739 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/log/MessageReporter.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/log/MessageReporter.java @@ -75,12 +75,14 @@ public interface MessageReporter { switch (this) { case ERROR: return java.util.logging.Level.SEVERE; - case INFO: - return java.util.logging.Level.INFO; - case TRACE: - return java.util.logging.Level.FINER; case WARN: return java.util.logging.Level.WARNING; + case INFO: + return java.util.logging.Level.INFO; + case DEBUG: + return java.util.logging.Level.FINE; + case TRACE: + return java.util.logging.Level.FINER; default: throw AssertionUtil.shouldNotReachHere("exhaustive"); } From 6f3dd6c11dbfc6a761aec7e8b5655828421814b4 Mon Sep 17 00:00:00 2001 From: jasonqiu98 Date: Thu, 31 Mar 2022 02:25:53 +0200 Subject: [PATCH 012/180] add release date on sidebar --- docs/_includes/sidebar.html | 1 + docs/css/pmd-customstyles.css | 6 ++++++ docs/css/theme-blue.css | 4 ++-- docs/css/theme-green.css | 4 ++-- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/docs/_includes/sidebar.html b/docs/_includes/sidebar.html index 0a3474f9ba..4220419313 100644 --- a/docs/_includes/sidebar.html +++ b/docs/_includes/sidebar.html @@ -2,6 +2,7 @@

*/ public static PmdAnalysis create(PMDConfiguration config) { - return create( - config, - new SimpleMessageReporter(LoggerFactory.getLogger(PmdAnalysis.class)) - ); - } - - @InternalApi - static PmdAnalysis create(PMDConfiguration config, MessageReporter reporter) { - PmdAnalysis pmd = new PmdAnalysis(config, reporter); + PmdAnalysis pmd = new PmdAnalysis(config); // note: do not filter files by language // they could be ignored later. The problem is if you call diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/SemanticErrorReporter.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/SemanticErrorReporter.java index 2dfe1ddb36..979ae36c6c 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/SemanticErrorReporter.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/SemanticErrorReporter.java @@ -9,6 +9,9 @@ import java.text.MessageFormat; import org.slf4j.Logger; import org.slf4j.event.Level; +import net.sourceforge.pmd.util.StringUtil; +import net.sourceforge.pmd.util.log.MessageReporter; + /** * Reports errors that occur after parsing. This may be used to implement * semantic checks in a language specific way. @@ -81,12 +84,17 @@ public interface SemanticErrorReporter { } - static SemanticErrorReporter reportToLogger(Logger logger) { + /** + * Forwards to a {@link MessageReporter}, except trace and debug + * messages which are reported on a logger. + */ + static SemanticErrorReporter reportToLogger(MessageReporter reporter, Logger logger) { return new SemanticErrorReporter() { private boolean hasError = false; private String locPrefix(Node loc) { - return "at " + loc.getAstInfo().getFileName() + " :" + loc.getBeginLine() + ":" + loc.getBeginColumn() + ": "; + return "at " + loc.getAstInfo().getFileName() + " :" + loc.getBeginLine() + ":" + loc.getBeginColumn() + + ": "; } private String makeMessage(Node location, String message, Object[] args) { @@ -95,7 +103,11 @@ public interface SemanticErrorReporter { private String logMessage(Level level, Node location, String message, Object[] args) { String fullMessage = makeMessage(location, message, args); - logger.atLevel(level).log(fullMessage); + if (level.compareTo(Level.INFO) < 0) { + logger.atLevel(level).log(fullMessage); + } else { + reporter.log(level, StringUtil.quoteMessageFormat(fullMessage)); // already formatted + } return fullMessage; } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/processor/PmdRunnable.java b/pmd-core/src/main/java/net/sourceforge/pmd/processor/PmdRunnable.java index ac4aec1b8f..20173a5247 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/processor/PmdRunnable.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/processor/PmdRunnable.java @@ -129,7 +129,7 @@ abstract class PmdRunnable implements Runnable { LanguageVersion languageVersion, String filename) throws FileAnalysisException { - SemanticErrorReporter reporter = SemanticErrorReporter.reportToLogger(LOGGER); + SemanticErrorReporter reporter = SemanticErrorReporter.reportToLogger(configuration.getReporter(), LOG); ParserTask task = new ParserTask( languageVersion, filename, diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/DummyLanguageModule.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/DummyLanguageModule.java index 3b9d4f6d72..c2a2a8a4b8 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/DummyLanguageModule.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/DummyLanguageModule.java @@ -11,6 +11,7 @@ import net.sourceforge.pmd.RuleViolation; import net.sourceforge.pmd.lang.ast.DummyRoot; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.ast.Parser; +import net.sourceforge.pmd.lang.ast.RootNode; import net.sourceforge.pmd.lang.rule.ParametricRuleViolation; import net.sourceforge.pmd.lang.rule.impl.DefaultRuleViolationFactory; @@ -34,6 +35,7 @@ public class DummyLanguageModule extends BaseLanguageModule { addDefaultVersion("1.7", new Handler(), "7"); addVersion("1.8", new Handler(), "8"); addVersion("1.9-throws", new HandlerWithParserThatThrows()); + addVersion("1.9-semantic_error", new HandlerWithParserThatReportsSemanticError()); } public static class Handler extends AbstractPmdLanguageVersionHandler { @@ -67,6 +69,17 @@ public class DummyLanguageModule extends BaseLanguageModule { } } + public static class HandlerWithParserThatReportsSemanticError extends Handler { + @Override + public Parser getParser() { + return task -> { + RootNode root = super.getParser().parse(task); + task.getReporter().error(root, "An error occurred!"); + return root; + }; + } + } + public static class RuleViolationFactory extends DefaultRuleViolationFactory { @Override diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/processor/PmdRunnableTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/processor/PmdRunnableTest.java index 4ef12433e3..fab2edd9ab 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/processor/PmdRunnableTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/processor/PmdRunnableTest.java @@ -7,6 +7,12 @@ package net.sourceforge.pmd.processor; import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasSize; +import static org.mockito.Mockito.contains; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; import java.util.List; @@ -15,6 +21,8 @@ import org.junit.Before; import org.junit.Test; import org.junit.contrib.java.lang.system.RestoreSystemProperties; import org.junit.rules.TestRule; +import org.mockito.Mockito; +import org.slf4j.event.Level; import net.sourceforge.pmd.PMDConfiguration; import net.sourceforge.pmd.Report; @@ -34,6 +42,7 @@ import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.rule.AbstractRule; import net.sourceforge.pmd.processor.MonoThreadProcessor.MonothreadRunnable; import net.sourceforge.pmd.util.datasource.DataSource; +import net.sourceforge.pmd.util.log.MessageReporter; public class PmdRunnableTest { @@ -42,20 +51,27 @@ public class PmdRunnableTest { private LanguageVersion dummyThrows; private LanguageVersion dummyDefault; + private LanguageVersion dummySemanticError; private PMDConfiguration configuration; private PmdRunnable pmdRunnable; private GlobalReportBuilderListener reportBuilder; + private MessageReporter reporter; + private Rule rule; @Before public void prepare() { Language dummyLanguage = LanguageRegistry.findLanguageByTerseName(DummyLanguageModule.TERSE_NAME); dummyDefault = dummyLanguage.getDefaultVersion(); dummyThrows = dummyLanguage.getVersion("1.9-throws"); + dummySemanticError = dummyLanguage.getVersion("1.9-semantic_error"); DataSource dataSource = DataSource.forString("test", "test.dummy"); - Rule rule = new RuleThatThrows(); + + rule = spy(new RuleThatThrows()); configuration = new PMDConfiguration(); reportBuilder = new GlobalReportBuilderListener(); + reporter = mock(MessageReporter.class); + configuration.setReporter(reporter); pmdRunnable = new MonothreadRunnable(new RuleSets(RuleSet.forSingleRule(rule)), dataSource, reportBuilder, @@ -102,6 +118,17 @@ public class PmdRunnableTest { Assert.assertThrows(AssertionError.class, pmdRunnable::run); } + + @Test + public void semanticErrorShouldAbortTheRun() { + configuration.setDefaultLanguageVersion(dummySemanticError); + + pmdRunnable.run(); + + verify(reporter).log(eq(Level.INFO), contains("skipping rule analysis")); + verify(rule, never()).apply(Mockito.any(), Mockito.any()); + } + private static class RuleThatThrows extends AbstractRule { RuleThatThrows() { diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/JavaParsingHelper.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/JavaParsingHelper.java index 3e9a884637..f6df0c19c9 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/JavaParsingHelper.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/JavaParsingHelper.java @@ -30,6 +30,8 @@ import net.sourceforge.pmd.lang.java.types.TypeSystem; import net.sourceforge.pmd.lang.java.types.internal.infer.TypeInferenceLogger; import net.sourceforge.pmd.lang.java.types.internal.infer.TypeInferenceLogger.SimpleLogger; import net.sourceforge.pmd.lang.java.types.internal.infer.TypeInferenceLogger.VerboseLogger; +import net.sourceforge.pmd.util.log.MessageReporter; +import net.sourceforge.pmd.util.log.internal.SimpleMessageReporter; import kotlin.Pair; @@ -110,12 +112,20 @@ public class JavaParsingHelper extends BaseParsingHelper Date: Thu, 14 Apr 2022 21:03:52 +0200 Subject: [PATCH 057/180] Add tests for Sem error reporter --- .../pmd/lang/ast/SemanticErrorReporter.java | 2 +- .../lang/ast/SemanticErrorReporterTest.java | 80 +++++++++++++++++++ 2 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/SemanticErrorReporterTest.java diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/SemanticErrorReporter.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/SemanticErrorReporter.java index 979ae36c6c..84df3a625c 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/SemanticErrorReporter.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/SemanticErrorReporter.java @@ -103,7 +103,7 @@ public interface SemanticErrorReporter { private String logMessage(Level level, Node location, String message, Object[] args) { String fullMessage = makeMessage(location, message, args); - if (level.compareTo(Level.INFO) < 0) { + if (level.compareTo(Level.INFO) > 0) { logger.atLevel(level).log(fullMessage); } else { reporter.log(level, StringUtil.quoteMessageFormat(fullMessage)); // already formatted diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/SemanticErrorReporterTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/SemanticErrorReporterTest.java new file mode 100644 index 0000000000..5497c9b93a --- /dev/null +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/SemanticErrorReporterTest.java @@ -0,0 +1,80 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ast; + +import static org.mockito.Mockito.contains; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.event.Level; +import org.slf4j.helpers.NOPLogger; + +import net.sourceforge.pmd.lang.DummyLanguageModule; +import net.sourceforge.pmd.lang.Language; +import net.sourceforge.pmd.lang.LanguageRegistry; +import net.sourceforge.pmd.lang.ast.Parser.ParserTask; +import net.sourceforge.pmd.util.log.MessageReporter; + +/** + * Reports errors that occur after parsing. This may be used to implement + * semantic checks in a language specific way. + */ +public class SemanticErrorReporterTest { + + private static final String MOCK_FILENAME = "dummy/file.txt"; + MessageReporter mockReporter; + Logger mockLogger; + + @Before + public void setup() { + mockReporter = mock(MessageReporter.class); + mockLogger = spy(NOPLogger.class); + } + + @Test + public void testErrorLogging() { + SemanticErrorReporter reporter = SemanticErrorReporter.reportToLogger(mockReporter, mockLogger); + RootNode node = parseMockNode(reporter); + + String message = "an error occurred"; + reporter.error(node, message); + + verify(mockReporter).log(eq(Level.ERROR), contains(message)); + verifyNoMoreInteractions(mockLogger); + } + + @Test + public void testEscaping() { + SemanticErrorReporter reporter = SemanticErrorReporter.reportToLogger(mockReporter, mockLogger); + RootNode node = parseMockNode(reporter); + + // this is a MessageFormat string + // what ends up being logged is just ' + String message = "an apostrophe '' "; + reporter.error(node, message); + + // The backend reporter will do its own formatting once again + verify(mockReporter).log(eq(Level.ERROR), contains("an apostrophe ''")); + verifyNoMoreInteractions(mockLogger); + } + + private RootNode parseMockNode(SemanticErrorReporter reporter) { + Language language = LanguageRegistry.getLanguage(DummyLanguageModule.NAME); + Parser parser = language.getDefaultVersion().getLanguageVersionHandler().getParser(); + return parser.parse(new ParserTask( + language.getDefaultVersion(), + MOCK_FILENAME, + "(mock (node))", + reporter + )); + } + +} From 6d152b1552c4d2f682f0cd7cedbb631746db0630 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Thu, 14 Apr 2022 21:23:19 +0200 Subject: [PATCH 058/180] Fix IndexOutOfBoundsException with lambda that has wrong shape --- .../lang/java/ast/ASTLambdaExpression.java | 7 ++++++ .../pmd/lang/java/ast/ASTLambdaParameter.java | 6 +++++ .../lang/java/types/ast/LazyTypeResolver.java | 3 +++ .../infer/UnresolvedTypesRecoveryTest.kt | 24 +++++++++++++++++++ .../ReturnEmptyCollectionRatherThanNull.xml | 4 ++-- 5 files changed, 42 insertions(+), 2 deletions(-) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLambdaExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLambdaExpression.java index 49fae5b924..df3d91f50e 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLambdaExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLambdaExpression.java @@ -110,6 +110,13 @@ public final class ASTLambdaExpression extends AbstractJavaExpr implements Funct } + /** + * Returns the number of formal parameters of this lambda. + */ + public int getArity() { + return getParameters().size(); + } + @Override protected R acceptVisitor(JavaVisitor visitor, P data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLambdaParameter.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLambdaParameter.java index cf5e3be93b..bae2b9c035 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLambdaParameter.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLambdaParameter.java @@ -41,6 +41,12 @@ public final class ASTLambdaParameter extends AbstractJavaTypeNode return visitor.visit(this, data); } + /** + * Returns the lambda that owns this parameter. + */ + public ASTLambdaExpression getOwner() { + return (ASTLambdaExpression) getParent().getParent(); + } /** * Returns the declarator ID of this formal parameter. diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/ast/LazyTypeResolver.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/ast/LazyTypeResolver.java index 9fa259f112..3b55c7af23 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/ast/LazyTypeResolver.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/ast/LazyTypeResolver.java @@ -565,6 +565,9 @@ public final class LazyTypeResolver extends JavaVisitorBase {}; // ok + Lambda l = x -> {}; // wrong form! + } + } + """) + + val (ok, wrong) = acu.descendants(ASTLambdaExpression::class.java).toList() + val t_Lambda = acu.typeDeclarations.firstOrThrow().typeMirror + + acu.withTypeDsl { + ok shouldHaveType t_Lambda + wrong shouldHaveType t_Lambda + wrong.parameters[0] shouldHaveType ts.ERROR + } + } + }) diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/ReturnEmptyCollectionRatherThanNull.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/ReturnEmptyCollectionRatherThanNull.xml index 5f90a26f72..effc4e57d1 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/ReturnEmptyCollectionRatherThanNull.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/ReturnEmptyCollectionRatherThanNull.xml @@ -191,7 +191,7 @@ import java.util.concurrent.*; import java.nio.file.Path; public class Foo { - private Map> joinFutures(Map>> map) { + private Map> joinFutures(Map>> map) { Map> joined = new HashMap<>(); for (String p : map.keySet()) { @@ -214,7 +214,7 @@ public class Foo { } // checking basic lambdas and anonymous classes as well - Callable c = a -> { return null; }; // <----- false positive here + Callable c = () -> { return null; }; // <----- false positive here Callable c2 = new Callable() { public Object call() { return null; // <----- false positive here From 6d2858da8e06ec5fc51fcaae8f878c6687fb8bc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Thu, 14 Apr 2022 21:30:24 +0200 Subject: [PATCH 059/180] Initial work to report typing errors in Java This should be done more thoroughly in a future PR --- .../pmd/lang/java/types/ast/LazyTypeResolver.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/ast/LazyTypeResolver.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/ast/LazyTypeResolver.java index 3b55c7af23..f25d15ff27 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/ast/LazyTypeResolver.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/ast/LazyTypeResolver.java @@ -15,6 +15,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import net.sourceforge.pmd.annotation.InternalApi; +import net.sourceforge.pmd.lang.ast.SemanticErrorReporter; import net.sourceforge.pmd.lang.java.ast.ASTAmbiguousName; import net.sourceforge.pmd.lang.java.ast.ASTAnnotation; import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration; @@ -100,15 +101,18 @@ public final class LazyTypeResolver extends JavaVisitorBase Date: Thu, 14 Apr 2022 21:38:52 +0200 Subject: [PATCH 060/180] Fix tree dump tests --- .../pmd/lang/java/ast/LambdaBug1333.txt | 2 +- .../pmd/lang/java/ast/LambdaBug1470.txt | 8 +-- .../pmd/lang/java/ast/ParserCornerCases18.txt | 66 +++++++++---------- .../java14/YieldStatements.txt | 2 +- .../jdkversiontests/java16/LocalRecords.txt | 4 +- 5 files changed, 41 insertions(+), 41 deletions(-) diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/LambdaBug1333.txt b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/LambdaBug1333.txt index 9611a35d64..2ba5fa1773 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/LambdaBug1333.txt +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/LambdaBug1333.txt @@ -20,7 +20,7 @@ | +- ExpressionStatement[] | +- MethodCall[@CompileTimeConstant = "false", @Image = "delete", @MethodName = "delete", @ParenthesisDepth = "0", @Parenthesized = "false"] | +- ArgumentList[@Empty = "false", @Size = "1"] - | +- LambdaExpression[@BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] + | +- LambdaExpression[@Arity = "1", @BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] | +- LambdaParameterList[@Empty = "false", @Size = "1"] | | +- LambdaParameter[@EffectiveVisibility = "package", @Final = "false", @TypeInferred = "true", @Visibility = "package"] | | +- ModifierList[@EffectiveModifiers = "{}", @ExplicitModifiers = "{}"] diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/LambdaBug1470.txt b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/LambdaBug1470.txt index a22e4f7c3b..eff4b29069 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/LambdaBug1470.txt +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/LambdaBug1470.txt @@ -24,7 +24,7 @@ | | +- TypeExpression[@CompileTimeConstant = "false", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | +- ClassOrInterfaceType[@FullyQualified = "false", @SimpleName = "Observable"] | | +- ArgumentList[@Empty = "false", @Size = "1"] - | | +- LambdaExpression[@BlockBody = "true", @CompileTimeConstant = "false", @ExpressionBody = "false", @ParenthesisDepth = "0", @Parenthesized = "false"] + | | +- LambdaExpression[@Arity = "1", @BlockBody = "true", @CompileTimeConstant = "false", @ExpressionBody = "false", @ParenthesisDepth = "0", @Parenthesized = "false"] | | +- LambdaParameterList[@Empty = "false", @Size = "1"] | | | +- LambdaParameter[@EffectiveVisibility = "package", @Final = "false", @TypeInferred = "false", @Visibility = "package"] | | | +- ModifierList[@EffectiveModifiers = "{}", @ExplicitModifiers = "{}"] @@ -39,7 +39,7 @@ | | +- VariableAccess[@AccessType = "WRITE", @CompileTimeConstant = "false", @Image = "stuff", @Name = "stuff", @ParenthesisDepth = "0", @Parenthesized = "false"] | | +- BooleanLiteral[@CompileTimeConstant = "true", @ParenthesisDepth = "0", @Parenthesized = "false", @True = "true"] | +- ArgumentList[@Empty = "false", @Size = "1"] - | +- LambdaExpression[@BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] + | +- LambdaExpression[@Arity = "1", @BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] | +- LambdaParameterList[@Empty = "false", @Size = "1"] | | +- LambdaParameter[@EffectiveVisibility = "package", @Final = "false", @TypeInferred = "true", @Visibility = "package"] | | +- ModifierList[@EffectiveModifiers = "{}", @ExplicitModifiers = "{}"] @@ -58,7 +58,7 @@ | +- TypeExpression[@CompileTimeConstant = "false", @ParenthesisDepth = "0", @Parenthesized = "false"] | | +- ClassOrInterfaceType[@FullyQualified = "false", @SimpleName = "Observable"] | +- ArgumentList[@Empty = "false", @Size = "1"] - | +- LambdaExpression[@BlockBody = "true", @CompileTimeConstant = "false", @ExpressionBody = "false", @ParenthesisDepth = "0", @Parenthesized = "false"] + | +- LambdaExpression[@Arity = "1", @BlockBody = "true", @CompileTimeConstant = "false", @ExpressionBody = "false", @ParenthesisDepth = "0", @Parenthesized = "false"] | +- LambdaParameterList[@Empty = "false", @Size = "1"] | | +- LambdaParameter[@EffectiveVisibility = "package", @Final = "false", @TypeInferred = "true", @Visibility = "package"] | | +- ModifierList[@EffectiveModifiers = "{}", @ExplicitModifiers = "{}"] @@ -69,7 +69,7 @@ | +- VariableAccess[@AccessType = "WRITE", @CompileTimeConstant = "false", @Image = "stuff", @Name = "stuff", @ParenthesisDepth = "0", @Parenthesized = "false"] | +- BooleanLiteral[@CompileTimeConstant = "true", @ParenthesisDepth = "0", @Parenthesized = "false", @True = "true"] +- ArgumentList[@Empty = "false", @Size = "1"] - +- LambdaExpression[@BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] + +- LambdaExpression[@Arity = "1", @BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] +- LambdaParameterList[@Empty = "false", @Size = "1"] | +- LambdaParameter[@EffectiveVisibility = "package", @Final = "false", @TypeInferred = "true", @Visibility = "package"] | +- ModifierList[@EffectiveModifiers = "{}", @ExplicitModifiers = "{}"] diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/ParserCornerCases18.txt b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/ParserCornerCases18.txt index 8db59987e3..5b8a8aadc2 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/ParserCornerCases18.txt +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/ParserCornerCases18.txt @@ -22,7 +22,7 @@ | | | +- ClassOrInterfaceType[@FullyQualified = "false", @SimpleName = "FileFilter"] | | | +- VariableDeclarator[@Initializer = "true", @Name = "java"] | | | +- VariableDeclaratorId[@ArrayType = "false", @EffectiveVisibility = "local", @EnumConstant = "false", @ExceptionBlockParameter = "false", @Field = "false", @Final = "false", @ForLoopVariable = "false", @ForeachVariable = "false", @FormalParameter = "false", @LambdaParameter = "false", @LocalVariable = "true", @Name = "java", @PatternBinding = "false", @RecordComponent = "false", @ResourceDeclaration = "false", @TypeInferred = "false", @Visibility = "local"] - | | | +- LambdaExpression[@BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] + | | | +- LambdaExpression[@Arity = "1", @BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | +- LambdaParameterList[@Empty = "false", @Size = "1"] | | | | +- LambdaParameter[@EffectiveVisibility = "package", @Final = "false", @TypeInferred = "false", @Visibility = "package"] | | | | +- ModifierList[@EffectiveModifiers = "{}", @ExplicitModifiers = "{}"] @@ -39,7 +39,7 @@ | | | +- ClassOrInterfaceType[@FullyQualified = "false", @SimpleName = "FileFilter"] | | | +- VariableDeclarator[@Initializer = "true", @Name = "java2"] | | | +- VariableDeclaratorId[@ArrayType = "false", @EffectiveVisibility = "local", @EnumConstant = "false", @ExceptionBlockParameter = "false", @Field = "false", @Final = "false", @ForLoopVariable = "false", @ForeachVariable = "false", @FormalParameter = "false", @LambdaParameter = "false", @LocalVariable = "true", @Name = "java2", @PatternBinding = "false", @RecordComponent = "false", @ResourceDeclaration = "false", @TypeInferred = "false", @Visibility = "local"] - | | | +- LambdaExpression[@BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] + | | | +- LambdaExpression[@Arity = "1", @BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | +- LambdaParameterList[@Empty = "false", @Size = "1"] | | | | +- LambdaParameter[@EffectiveVisibility = "package", @Final = "false", @TypeInferred = "true", @Visibility = "package"] | | | | +- ModifierList[@EffectiveModifiers = "{}", @ExplicitModifiers = "{}"] @@ -55,7 +55,7 @@ | | | +- ClassOrInterfaceType[@FullyQualified = "false", @SimpleName = "FileFilter"] | | | +- VariableDeclarator[@Initializer = "true", @Name = "java3"] | | | +- VariableDeclaratorId[@ArrayType = "false", @EffectiveVisibility = "local", @EnumConstant = "false", @ExceptionBlockParameter = "false", @Field = "false", @Final = "false", @ForLoopVariable = "false", @ForeachVariable = "false", @FormalParameter = "false", @LambdaParameter = "false", @LocalVariable = "true", @Name = "java3", @PatternBinding = "false", @RecordComponent = "false", @ResourceDeclaration = "false", @TypeInferred = "false", @Visibility = "local"] - | | | +- LambdaExpression[@BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] + | | | +- LambdaExpression[@Arity = "1", @BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | +- LambdaParameterList[@Empty = "false", @Size = "1"] | | | | +- LambdaParameter[@EffectiveVisibility = "package", @Final = "false", @TypeInferred = "true", @Visibility = "package"] | | | | +- ModifierList[@EffectiveModifiers = "{}", @ExplicitModifiers = "{}"] @@ -71,7 +71,7 @@ | | | +- ClassOrInterfaceType[@FullyQualified = "false", @SimpleName = "FileFilter"] | | | +- VariableDeclarator[@Initializer = "true", @Name = "java4"] | | | +- VariableDeclaratorId[@ArrayType = "false", @EffectiveVisibility = "local", @EnumConstant = "false", @ExceptionBlockParameter = "false", @Field = "false", @Final = "false", @ForLoopVariable = "false", @ForeachVariable = "false", @FormalParameter = "false", @LambdaParameter = "false", @LocalVariable = "true", @Name = "java4", @PatternBinding = "false", @RecordComponent = "false", @ResourceDeclaration = "false", @TypeInferred = "false", @Visibility = "local"] - | | | +- LambdaExpression[@BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "1", @Parenthesized = "true"] + | | | +- LambdaExpression[@Arity = "1", @BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "1", @Parenthesized = "true"] | | | +- LambdaParameterList[@Empty = "false", @Size = "1"] | | | | +- LambdaParameter[@EffectiveVisibility = "package", @Final = "false", @TypeInferred = "true", @Visibility = "package"] | | | | +- ModifierList[@EffectiveModifiers = "{}", @ExplicitModifiers = "{}"] @@ -93,7 +93,7 @@ | | | | | +- AmbiguousName[@CompileTimeConstant = "false", @Image = "array", @Name = "array", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | | +- ArgumentList[@Empty = "true", @Size = "0"] | | | +- ArgumentList[@Empty = "false", @Size = "1"] - | | | +- LambdaExpression[@BlockBody = "true", @CompileTimeConstant = "false", @ExpressionBody = "false", @ParenthesisDepth = "0", @Parenthesized = "false"] + | | | +- LambdaExpression[@Arity = "1", @BlockBody = "true", @CompileTimeConstant = "false", @ExpressionBody = "false", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | +- LambdaParameterList[@Empty = "false", @Size = "1"] | | | | +- LambdaParameter[@EffectiveVisibility = "package", @Final = "false", @TypeInferred = "true", @Visibility = "package"] | | | | +- ModifierList[@EffectiveModifiers = "{}", @ExplicitModifiers = "{}"] @@ -122,7 +122,7 @@ | | | | +- ArrayDimensions[@Empty = "false", @Size = "1"] | | | | +- ArrayTypeDim[@Varargs = "false"] | | | +- ArrayInitializer[@CompileTimeConstant = "false", @Length = "3", @ParenthesisDepth = "0", @Parenthesized = "false"] - | | | +- LambdaExpression[@BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] + | | | +- LambdaExpression[@Arity = "1", @BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | | +- LambdaParameterList[@Empty = "false", @Size = "1"] | | | | | +- LambdaParameter[@EffectiveVisibility = "package", @Final = "false", @TypeInferred = "true", @Visibility = "package"] | | | | | +- ModifierList[@EffectiveModifiers = "{}", @ExplicitModifiers = "{}"] @@ -130,7 +130,7 @@ | | | | +- MethodCall[@CompileTimeConstant = "false", @Image = "exists", @MethodName = "exists", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | | +- VariableAccess[@AccessType = "READ", @CompileTimeConstant = "false", @Image = "f", @Name = "f", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | | +- ArgumentList[@Empty = "true", @Size = "0"] - | | | +- LambdaExpression[@BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] + | | | +- LambdaExpression[@Arity = "1", @BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | | +- LambdaParameterList[@Empty = "false", @Size = "1"] | | | | | +- LambdaParameter[@EffectiveVisibility = "package", @Final = "false", @TypeInferred = "true", @Visibility = "package"] | | | | | +- ModifierList[@EffectiveModifiers = "{}", @ExplicitModifiers = "{}"] @@ -138,7 +138,7 @@ | | | | +- MethodCall[@CompileTimeConstant = "false", @Image = "canRead", @MethodName = "canRead", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | | +- VariableAccess[@AccessType = "READ", @CompileTimeConstant = "false", @Image = "f", @Name = "f", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | | +- ArgumentList[@Empty = "true", @Size = "0"] - | | | +- LambdaExpression[@BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] + | | | +- LambdaExpression[@Arity = "1", @BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | +- LambdaParameterList[@Empty = "false", @Size = "1"] | | | | +- LambdaParameter[@EffectiveVisibility = "package", @Final = "false", @TypeInferred = "true", @Visibility = "package"] | | | | +- ModifierList[@EffectiveModifiers = "{}", @ExplicitModifiers = "{}"] @@ -158,7 +158,7 @@ | | | | +- ArrayDimensions[@Empty = "false", @Size = "1"] | | | | +- ArrayTypeDim[@Varargs = "false"] | | | +- ArrayInitializer[@CompileTimeConstant = "false", @Length = "3", @ParenthesisDepth = "0", @Parenthesized = "false"] - | | | +- LambdaExpression[@BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] + | | | +- LambdaExpression[@Arity = "1", @BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | | +- LambdaParameterList[@Empty = "false", @Size = "1"] | | | | | +- LambdaParameter[@EffectiveVisibility = "package", @Final = "false", @TypeInferred = "true", @Visibility = "package"] | | | | | +- ModifierList[@EffectiveModifiers = "{}", @ExplicitModifiers = "{}"] @@ -166,7 +166,7 @@ | | | | +- MethodCall[@CompileTimeConstant = "false", @Image = "exists", @MethodName = "exists", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | | +- VariableAccess[@AccessType = "READ", @CompileTimeConstant = "false", @Image = "f", @Name = "f", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | | +- ArgumentList[@Empty = "true", @Size = "0"] - | | | +- LambdaExpression[@BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] + | | | +- LambdaExpression[@Arity = "1", @BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | | +- LambdaParameterList[@Empty = "false", @Size = "1"] | | | | | +- LambdaParameter[@EffectiveVisibility = "package", @Final = "false", @TypeInferred = "true", @Visibility = "package"] | | | | | +- ModifierList[@EffectiveModifiers = "{}", @ExplicitModifiers = "{}"] @@ -174,7 +174,7 @@ | | | | +- MethodCall[@CompileTimeConstant = "false", @Image = "canRead", @MethodName = "canRead", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | | +- VariableAccess[@AccessType = "READ", @CompileTimeConstant = "false", @Image = "f", @Name = "f", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | | +- ArgumentList[@Empty = "true", @Size = "0"] - | | | +- LambdaExpression[@BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] + | | | +- LambdaExpression[@Arity = "1", @BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | +- LambdaParameterList[@Empty = "false", @Size = "1"] | | | | +- LambdaParameter[@EffectiveVisibility = "package", @Final = "false", @TypeInferred = "true", @Visibility = "package"] | | | | +- ModifierList[@EffectiveModifiers = "{}", @ExplicitModifiers = "{}"] @@ -192,7 +192,7 @@ | | | +- VariableDeclaratorId[@ArrayType = "false", @EffectiveVisibility = "local", @EnumConstant = "false", @ExceptionBlockParameter = "false", @Field = "false", @Final = "false", @ForLoopVariable = "false", @ForeachVariable = "false", @FormalParameter = "false", @LambdaParameter = "false", @LocalVariable = "true", @Name = "user", @PatternBinding = "false", @RecordComponent = "false", @ResourceDeclaration = "false", @TypeInferred = "false", @Visibility = "local"] | | | +- MethodCall[@CompileTimeConstant = "false", @Image = "doPrivileged", @MethodName = "doPrivileged", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | +- ArgumentList[@Empty = "false", @Size = "1"] - | | | +- LambdaExpression[@BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] + | | | +- LambdaExpression[@Arity = "0", @BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | +- LambdaParameterList[@Empty = "true", @Size = "0"] | | | +- MethodCall[@CompileTimeConstant = "false", @Image = "getProperty", @MethodName = "getProperty", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | +- TypeExpression[@CompileTimeConstant = "false", @ParenthesisDepth = "0", @Parenthesized = "false"] @@ -206,7 +206,7 @@ | | | | +- ClassOrInterfaceType[@FullyQualified = "false", @SimpleName = "String"] | | | +- VariableDeclarator[@Initializer = "true", @Name = "c"] | | | +- VariableDeclaratorId[@ArrayType = "false", @EffectiveVisibility = "local", @EnumConstant = "false", @ExceptionBlockParameter = "false", @Field = "false", @Final = "false", @ForLoopVariable = "false", @ForeachVariable = "false", @FormalParameter = "false", @LambdaParameter = "false", @LocalVariable = "true", @Name = "c", @PatternBinding = "false", @RecordComponent = "false", @ResourceDeclaration = "false", @TypeInferred = "false", @Visibility = "local"] - | | | +- LambdaExpression[@BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] + | | | +- LambdaExpression[@Arity = "0", @BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | +- LambdaParameterList[@Empty = "true", @Size = "0"] | | | +- StringLiteral[@CompileTimeConstant = "true", @ConstValue = "done", @Empty = "false", @Image = "\"done\"", @Length = "4", @ParenthesisDepth = "0", @Parenthesized = "false", @TextBlock = "false"] | | +- LocalVariableDeclaration[@EffectiveVisibility = "local", @Final = "false", @TypeInferred = "false", @Visibility = "local"] @@ -214,7 +214,7 @@ | | | +- ClassOrInterfaceType[@FullyQualified = "false", @SimpleName = "Runnable"] | | | +- VariableDeclarator[@Initializer = "true", @Name = "r"] | | | +- VariableDeclaratorId[@ArrayType = "false", @EffectiveVisibility = "local", @EnumConstant = "false", @ExceptionBlockParameter = "false", @Field = "false", @Final = "false", @ForLoopVariable = "false", @ForeachVariable = "false", @FormalParameter = "false", @LambdaParameter = "false", @LocalVariable = "true", @Name = "r", @PatternBinding = "false", @RecordComponent = "false", @ResourceDeclaration = "false", @TypeInferred = "false", @Visibility = "local"] - | | | +- LambdaExpression[@BlockBody = "true", @CompileTimeConstant = "false", @ExpressionBody = "false", @ParenthesisDepth = "0", @Parenthesized = "false"] + | | | +- LambdaExpression[@Arity = "0", @BlockBody = "true", @CompileTimeConstant = "false", @ExpressionBody = "false", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | +- LambdaParameterList[@Empty = "true", @Size = "0"] | | | +- Block[@Empty = "false", @Size = "1", @containsComment = "false"] | | | +- ExpressionStatement[] @@ -231,9 +231,9 @@ | | | | +- ClassOrInterfaceType[@FullyQualified = "false", @SimpleName = "Runnable"] | | | +- VariableDeclarator[@Initializer = "true", @Name = "sup"] | | | +- VariableDeclaratorId[@ArrayType = "false", @EffectiveVisibility = "local", @EnumConstant = "false", @ExceptionBlockParameter = "false", @Field = "false", @Final = "false", @ForLoopVariable = "false", @ForeachVariable = "false", @FormalParameter = "false", @LambdaParameter = "false", @LocalVariable = "true", @Name = "sup", @PatternBinding = "false", @RecordComponent = "false", @ResourceDeclaration = "false", @TypeInferred = "false", @Visibility = "local"] - | | | +- LambdaExpression[@BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] + | | | +- LambdaExpression[@Arity = "0", @BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | +- LambdaParameterList[@Empty = "true", @Size = "0"] - | | | +- LambdaExpression[@BlockBody = "true", @CompileTimeConstant = "false", @ExpressionBody = "false", @ParenthesisDepth = "0", @Parenthesized = "false"] + | | | +- LambdaExpression[@Arity = "0", @BlockBody = "true", @CompileTimeConstant = "false", @ExpressionBody = "false", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | +- LambdaParameterList[@Empty = "true", @Size = "0"] | | | +- Block[@Empty = "false", @Size = "1", @containsComment = "false"] | | | +- ExpressionStatement[] @@ -260,10 +260,10 @@ | | | +- VariableDeclaratorId[@ArrayType = "false", @EffectiveVisibility = "local", @EnumConstant = "false", @ExceptionBlockParameter = "false", @Field = "false", @Final = "false", @ForLoopVariable = "false", @ForeachVariable = "false", @FormalParameter = "false", @LambdaParameter = "false", @LocalVariable = "true", @Name = "c2", @PatternBinding = "false", @RecordComponent = "false", @ResourceDeclaration = "false", @TypeInferred = "false", @Visibility = "local"] | | | +- ConditionalExpression[@CompileTimeConstant = "false", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | +- VariableAccess[@AccessType = "READ", @CompileTimeConstant = "false", @Image = "flag", @Name = "flag", @ParenthesisDepth = "0", @Parenthesized = "false"] - | | | +- LambdaExpression[@BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "1", @Parenthesized = "true"] + | | | +- LambdaExpression[@Arity = "0", @BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "1", @Parenthesized = "true"] | | | | +- LambdaParameterList[@Empty = "true", @Size = "0"] | | | | +- NumericLiteral[@Base = "10", @CompileTimeConstant = "true", @DoubleLiteral = "false", @FloatLiteral = "false", @Image = "23", @IntLiteral = "true", @Integral = "true", @LongLiteral = "false", @ParenthesisDepth = "0", @Parenthesized = "false", @ValueAsDouble = "23.0", @ValueAsFloat = "23.0", @ValueAsInt = "23", @ValueAsLong = "23"] - | | | +- LambdaExpression[@BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "1", @Parenthesized = "true"] + | | | +- LambdaExpression[@Arity = "0", @BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "1", @Parenthesized = "true"] | | | +- LambdaParameterList[@Empty = "true", @Size = "0"] | | | +- NumericLiteral[@Base = "10", @CompileTimeConstant = "true", @DoubleLiteral = "false", @FloatLiteral = "false", @Image = "42", @IntLiteral = "true", @Integral = "true", @LongLiteral = "false", @ParenthesisDepth = "0", @Parenthesized = "false", @ValueAsDouble = "42.0", @ValueAsFloat = "42.0", @ValueAsInt = "42", @ValueAsLong = "42"] | | +- LocalVariableDeclaration[@EffectiveVisibility = "local", @Final = "false", @TypeInferred = "false", @Visibility = "local"] @@ -273,7 +273,7 @@ | | | +- VariableDeclaratorId[@ArrayType = "false", @EffectiveVisibility = "local", @EnumConstant = "false", @ExceptionBlockParameter = "false", @Field = "false", @Final = "false", @ForLoopVariable = "false", @ForeachVariable = "false", @FormalParameter = "false", @LambdaParameter = "false", @LocalVariable = "true", @Name = "o", @PatternBinding = "false", @RecordComponent = "false", @ResourceDeclaration = "false", @TypeInferred = "false", @Visibility = "local"] | | | +- CastExpression[@CompileTimeConstant = "false", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | +- ClassOrInterfaceType[@FullyQualified = "false", @SimpleName = "Runnable"] - | | | +- LambdaExpression[@BlockBody = "true", @CompileTimeConstant = "false", @ExpressionBody = "false", @ParenthesisDepth = "0", @Parenthesized = "false"] + | | | +- LambdaExpression[@Arity = "0", @BlockBody = "true", @CompileTimeConstant = "false", @ExpressionBody = "false", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | +- LambdaParameterList[@Empty = "true", @Size = "0"] | | | +- Block[@Empty = "false", @Size = "1", @containsComment = "false"] | | | +- ExpressionStatement[] @@ -297,7 +297,7 @@ | | | | +- ClassOrInterfaceType[@FullyQualified = "false", @SimpleName = "String"] | | | +- VariableDeclarator[@Initializer = "true", @Name = "comparer"] | | | +- VariableDeclaratorId[@ArrayType = "false", @EffectiveVisibility = "local", @EnumConstant = "false", @ExceptionBlockParameter = "false", @Field = "false", @Final = "false", @ForLoopVariable = "false", @ForeachVariable = "false", @FormalParameter = "false", @LambdaParameter = "false", @LocalVariable = "true", @Name = "comparer", @PatternBinding = "false", @RecordComponent = "false", @ResourceDeclaration = "false", @TypeInferred = "false", @Visibility = "local"] - | | | +- LambdaExpression[@BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] + | | | +- LambdaExpression[@Arity = "2", @BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | +- LambdaParameterList[@Empty = "false", @Size = "2"] | | | | +- LambdaParameter[@EffectiveVisibility = "package", @Final = "false", @TypeInferred = "true", @Visibility = "package"] | | | | | +- ModifierList[@EffectiveModifiers = "{}", @ExplicitModifiers = "{}"] @@ -312,7 +312,7 @@ | | +- ExpressionStatement[] | | | +- AssignmentExpression[@CompileTimeConstant = "false", @Compound = "false", @Operator = "=", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | +- VariableAccess[@AccessType = "WRITE", @CompileTimeConstant = "false", @Image = "comparer", @Name = "comparer", @ParenthesisDepth = "0", @Parenthesized = "false"] - | | | +- LambdaExpression[@BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] + | | | +- LambdaExpression[@Arity = "2", @BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | +- LambdaParameterList[@Empty = "false", @Size = "2"] | | | | +- LambdaParameter[@EffectiveVisibility = "package", @Final = "false", @TypeInferred = "true", @Visibility = "package"] | | | | | +- ModifierList[@EffectiveModifiers = "{}", @ExplicitModifiers = "{}"] @@ -336,7 +336,7 @@ | | | +- MethodCall[@CompileTimeConstant = "false", @Image = "addActionListener", @MethodName = "addActionListener", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | +- VariableAccess[@AccessType = "READ", @CompileTimeConstant = "false", @Image = "button", @Name = "button", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | +- ArgumentList[@Empty = "false", @Size = "1"] - | | | +- LambdaExpression[@BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] + | | | +- LambdaExpression[@Arity = "1", @BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | +- LambdaParameterList[@Empty = "false", @Size = "1"] | | | | +- LambdaParameter[@EffectiveVisibility = "package", @Final = "false", @TypeInferred = "true", @Visibility = "package"] | | | | +- ModifierList[@EffectiveModifiers = "{}", @ExplicitModifiers = "{}"] @@ -371,7 +371,7 @@ | | | | +- ClassOrInterfaceType[@FullyQualified = "false", @SimpleName = "Integer"] | | | +- VariableDeclarator[@Initializer = "true", @Name = "lambda2"] | | | +- VariableDeclaratorId[@ArrayType = "false", @EffectiveVisibility = "local", @EnumConstant = "false", @ExceptionBlockParameter = "false", @Field = "false", @Final = "false", @ForLoopVariable = "false", @ForeachVariable = "false", @FormalParameter = "false", @LambdaParameter = "false", @LocalVariable = "true", @Name = "lambda2", @PatternBinding = "false", @RecordComponent = "false", @ResourceDeclaration = "false", @TypeInferred = "false", @Visibility = "local"] - | | | +- LambdaExpression[@BlockBody = "true", @CompileTimeConstant = "false", @ExpressionBody = "false", @ParenthesisDepth = "0", @Parenthesized = "false"] + | | | +- LambdaExpression[@Arity = "2", @BlockBody = "true", @CompileTimeConstant = "false", @ExpressionBody = "false", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | +- LambdaParameterList[@Empty = "false", @Size = "2"] | | | | +- LambdaParameter[@EffectiveVisibility = "package", @Final = "false", @TypeInferred = "false", @Visibility = "package"] | | | | | +- ModifierList[@EffectiveModifiers = "{}", @ExplicitModifiers = "{}"] @@ -393,7 +393,7 @@ | | | | +- ClassOrInterfaceType[@FullyQualified = "false", @SimpleName = "Integer"] | | | +- VariableDeclarator[@Initializer = "true", @Name = "lambda2a"] | | | +- VariableDeclaratorId[@ArrayType = "false", @EffectiveVisibility = "local", @EnumConstant = "false", @ExceptionBlockParameter = "false", @Field = "false", @Final = "false", @ForLoopVariable = "false", @ForeachVariable = "false", @FormalParameter = "false", @LambdaParameter = "false", @LocalVariable = "true", @Name = "lambda2a", @PatternBinding = "false", @RecordComponent = "false", @ResourceDeclaration = "false", @TypeInferred = "false", @Visibility = "local"] - | | | +- LambdaExpression[@BlockBody = "true", @CompileTimeConstant = "false", @ExpressionBody = "false", @ParenthesisDepth = "0", @Parenthesized = "false"] + | | | +- LambdaExpression[@Arity = "2", @BlockBody = "true", @CompileTimeConstant = "false", @ExpressionBody = "false", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | +- LambdaParameterList[@Empty = "false", @Size = "2"] | | | | +- LambdaParameter[@EffectiveVisibility = "package", @Final = "false", @TypeInferred = "true", @Visibility = "package"] | | | | | +- ModifierList[@EffectiveModifiers = "{}", @ExplicitModifiers = "{}"] @@ -414,7 +414,7 @@ | | | | +- ClassOrInterfaceType[@FullyQualified = "false", @SimpleName = "Double"] | | | +- VariableDeclarator[@Initializer = "true", @Name = "lambda3"] | | | +- VariableDeclaratorId[@ArrayType = "false", @EffectiveVisibility = "local", @EnumConstant = "false", @ExceptionBlockParameter = "false", @Field = "false", @Final = "false", @ForLoopVariable = "false", @ForeachVariable = "false", @FormalParameter = "false", @LambdaParameter = "false", @LocalVariable = "true", @Name = "lambda3", @PatternBinding = "false", @RecordComponent = "false", @ResourceDeclaration = "false", @TypeInferred = "false", @Visibility = "local"] - | | | +- LambdaExpression[@BlockBody = "true", @CompileTimeConstant = "false", @ExpressionBody = "false", @ParenthesisDepth = "0", @Parenthesized = "false"] + | | | +- LambdaExpression[@Arity = "3", @BlockBody = "true", @CompileTimeConstant = "false", @ExpressionBody = "false", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | +- LambdaParameterList[@Empty = "false", @Size = "3"] | | | | +- LambdaParameter[@EffectiveVisibility = "package", @Final = "false", @TypeInferred = "false", @Visibility = "package"] | | | | | +- ModifierList[@EffectiveModifiers = "{}", @ExplicitModifiers = "{}"] @@ -442,7 +442,7 @@ | | | +- ClassOrInterfaceType[@FullyQualified = "false", @SimpleName = "Double"] | | +- VariableDeclarator[@Initializer = "true", @Name = "lambda3a"] | | +- VariableDeclaratorId[@ArrayType = "false", @EffectiveVisibility = "local", @EnumConstant = "false", @ExceptionBlockParameter = "false", @Field = "false", @Final = "false", @ForLoopVariable = "false", @ForeachVariable = "false", @FormalParameter = "false", @LambdaParameter = "false", @LocalVariable = "true", @Name = "lambda3a", @PatternBinding = "false", @RecordComponent = "false", @ResourceDeclaration = "false", @TypeInferred = "false", @Visibility = "local"] - | | +- LambdaExpression[@BlockBody = "true", @CompileTimeConstant = "false", @ExpressionBody = "false", @ParenthesisDepth = "0", @Parenthesized = "false"] + | | +- LambdaExpression[@Arity = "3", @BlockBody = "true", @CompileTimeConstant = "false", @ExpressionBody = "false", @ParenthesisDepth = "0", @Parenthesized = "false"] | | +- LambdaParameterList[@Empty = "false", @Size = "3"] | | | +- LambdaParameter[@EffectiveVisibility = "package", @Final = "false", @TypeInferred = "true", @Visibility = "package"] | | | | +- ModifierList[@EffectiveModifiers = "{}", @ExplicitModifiers = "{}"] @@ -488,7 +488,7 @@ | | +- ClassOrInterfaceType[@FullyQualified = "false", @SimpleName = "Runnable"] | | +- VariableDeclarator[@Initializer = "true", @Name = "r1"] | | +- VariableDeclaratorId[@ArrayType = "false", @EffectiveVisibility = "package", @EnumConstant = "false", @ExceptionBlockParameter = "false", @Field = "true", @Final = "false", @ForLoopVariable = "false", @ForeachVariable = "false", @FormalParameter = "false", @LambdaParameter = "false", @LocalVariable = "false", @Name = "r1", @PatternBinding = "false", @RecordComponent = "false", @ResourceDeclaration = "false", @TypeInferred = "false", @Visibility = "package"] - | | +- LambdaExpression[@BlockBody = "true", @CompileTimeConstant = "false", @ExpressionBody = "false", @ParenthesisDepth = "0", @Parenthesized = "false"] + | | +- LambdaExpression[@Arity = "0", @BlockBody = "true", @CompileTimeConstant = "false", @ExpressionBody = "false", @ParenthesisDepth = "0", @Parenthesized = "false"] | | +- LambdaParameterList[@Empty = "true", @Size = "0"] | | +- Block[@Empty = "false", @Size = "1", @containsComment = "false"] | | +- ExpressionStatement[] @@ -504,7 +504,7 @@ | | +- FormalParameters[@Empty = "true", @Size = "0"] | | +- Block[@Empty = "false", @Size = "1", @containsComment = "false"] | | +- ReturnStatement[] - | | +- LambdaExpression[@BlockBody = "true", @CompileTimeConstant = "false", @ExpressionBody = "false", @ParenthesisDepth = "0", @Parenthesized = "false"] + | | +- LambdaExpression[@Arity = "0", @BlockBody = "true", @CompileTimeConstant = "false", @ExpressionBody = "false", @ParenthesisDepth = "0", @Parenthesized = "false"] | | +- LambdaParameterList[@Empty = "true", @Size = "0"] | | +- Block[@Empty = "false", @Size = "1", @containsComment = "false"] | | +- ExpressionStatement[] @@ -568,7 +568,7 @@ | | | | +- ClassOrInterfaceType[@FullyQualified = "false", @SimpleName = "K"] | | | | +- ClassOrInterfaceType[@FullyQualified = "false", @SimpleName = "V"] | | | +- ClassOrInterfaceType[@FullyQualified = "false", @SimpleName = "Serializable"] - | | +- LambdaExpression[@BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] + | | +- LambdaExpression[@Arity = "2", @BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] | | +- LambdaParameterList[@Empty = "false", @Size = "2"] | | | +- LambdaParameter[@EffectiveVisibility = "package", @Final = "false", @TypeInferred = "true", @Visibility = "package"] | | | | +- ModifierList[@EffectiveModifiers = "{}", @ExplicitModifiers = "{}"] @@ -702,7 +702,7 @@ | | +- FormalParameters[@Empty = "true", @Size = "0"] | | +- Block[@Empty = "false", @Size = "1", @containsComment = "false"] | | +- ReturnStatement[] - | | +- LambdaExpression[@BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] + | | +- LambdaExpression[@Arity = "0", @BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] | | +- LambdaParameterList[@Empty = "true", @Size = "0"] | | +- MethodCall[@CompileTimeConstant = "false", @Image = "println", @MethodName = "println", @ParenthesisDepth = "0", @Parenthesized = "false"] | | +- FieldAccess[@AccessType = "READ", @CompileTimeConstant = "false", @Image = "out", @Name = "out", @ParenthesisDepth = "0", @Parenthesized = "false"] @@ -776,7 +776,7 @@ | | | | | +- NumericLiteral[@Base = "10", @CompileTimeConstant = "true", @DoubleLiteral = "false", @FloatLiteral = "false", @Image = "2", @IntLiteral = "true", @Integral = "true", @LongLiteral = "false", @ParenthesisDepth = "0", @Parenthesized = "false", @ValueAsDouble = "2.0", @ValueAsFloat = "2.0", @ValueAsInt = "2", @ValueAsLong = "2"] | | | | | +- NumericLiteral[@Base = "10", @CompileTimeConstant = "true", @DoubleLiteral = "false", @FloatLiteral = "false", @Image = "3", @IntLiteral = "true", @Integral = "true", @LongLiteral = "false", @ParenthesisDepth = "0", @Parenthesized = "false", @ValueAsDouble = "3.0", @ValueAsFloat = "3.0", @ValueAsInt = "3", @ValueAsLong = "3"] | | | | +- ArgumentList[@Empty = "false", @Size = "1"] - | | | | +- LambdaExpression[@BlockBody = "true", @CompileTimeConstant = "false", @ExpressionBody = "false", @ParenthesisDepth = "0", @Parenthesized = "false"] + | | | | +- LambdaExpression[@Arity = "2", @BlockBody = "true", @CompileTimeConstant = "false", @ExpressionBody = "false", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | | +- LambdaParameterList[@Empty = "false", @Size = "2"] | | | | | +- LambdaParameter[@EffectiveVisibility = "package", @Final = "false", @TypeInferred = "true", @Visibility = "package"] | | | | | | +- ModifierList[@EffectiveModifiers = "{}", @ExplicitModifiers = "{}"] @@ -827,7 +827,7 @@ | | | | | +- NumericLiteral[@Base = "10", @CompileTimeConstant = "true", @DoubleLiteral = "false", @FloatLiteral = "false", @Image = "2", @IntLiteral = "true", @Integral = "true", @LongLiteral = "false", @ParenthesisDepth = "0", @Parenthesized = "false", @ValueAsDouble = "2.0", @ValueAsFloat = "2.0", @ValueAsInt = "2", @ValueAsLong = "2"] | | | | | +- NumericLiteral[@Base = "10", @CompileTimeConstant = "true", @DoubleLiteral = "false", @FloatLiteral = "false", @Image = "3", @IntLiteral = "true", @Integral = "true", @LongLiteral = "false", @ParenthesisDepth = "0", @Parenthesized = "false", @ValueAsDouble = "3.0", @ValueAsFloat = "3.0", @ValueAsInt = "3", @ValueAsLong = "3"] | | | | +- ArgumentList[@Empty = "false", @Size = "1"] - | | | | +- LambdaExpression[@BlockBody = "true", @CompileTimeConstant = "false", @ExpressionBody = "false", @ParenthesisDepth = "0", @Parenthesized = "false"] + | | | | +- LambdaExpression[@Arity = "2", @BlockBody = "true", @CompileTimeConstant = "false", @ExpressionBody = "false", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | | +- LambdaParameterList[@Empty = "false", @Size = "2"] | | | | | +- LambdaParameter[@EffectiveVisibility = "package", @Final = "false", @TypeInferred = "false", @Visibility = "package"] | | | | | | +- ModifierList[@EffectiveModifiers = "{}", @ExplicitModifiers = "{}"] @@ -873,7 +873,7 @@ | | +- AssignmentExpression[@CompileTimeConstant = "false", @Compound = "false", @Operator = "=", @ParenthesisDepth = "0", @Parenthesized = "false"] | | +- FieldAccess[@AccessType = "WRITE", @CompileTimeConstant = "false", @Image = "event", @Name = "event", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | +- AmbiguousName[@CompileTimeConstant = "false", @Image = "object", @Name = "object", @ParenthesisDepth = "0", @Parenthesized = "false"] - | | +- LambdaExpression[@BlockBody = "true", @CompileTimeConstant = "false", @ExpressionBody = "false", @ParenthesisDepth = "0", @Parenthesized = "false"] + | | +- LambdaExpression[@Arity = "0", @BlockBody = "true", @CompileTimeConstant = "false", @ExpressionBody = "false", @ParenthesisDepth = "0", @Parenthesized = "false"] | | +- LambdaParameterList[@Empty = "true", @Size = "0"] | | +- Block[@Empty = "false", @Size = "2", @containsComment = "true"] | | +- LocalVariableDeclaration[@EffectiveVisibility = "local", @Final = "false", @TypeInferred = "false", @Visibility = "local"] diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/YieldStatements.txt b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/YieldStatements.txt index 16419dfa5a..94c8ba1742 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/YieldStatements.txt +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/YieldStatements.txt @@ -73,7 +73,7 @@ | +- YieldStatement[] | +- NumericLiteral[@Base = "10", @CompileTimeConstant = "true", @DoubleLiteral = "false", @FloatLiteral = "false", @Image = "5", @IntLiteral = "true", @Integral = "true", @LongLiteral = "false", @ParenthesisDepth = "1", @Parenthesized = "true", @ValueAsDouble = "5.0", @ValueAsFloat = "5.0", @ValueAsInt = "5", @ValueAsLong = "5"] +- YieldStatement[] - | +- LambdaExpression[@BlockBody = "true", @CompileTimeConstant = "false", @ExpressionBody = "false", @ParenthesisDepth = "0", @Parenthesized = "false"] + | +- LambdaExpression[@Arity = "0", @BlockBody = "true", @CompileTimeConstant = "false", @ExpressionBody = "false", @ParenthesisDepth = "0", @Parenthesized = "false"] | +- LambdaParameterList[@Empty = "true", @Size = "0"] | +- Block[@Empty = "true", @Size = "0", @containsComment = "false"] +- ExpressionStatement[] diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/LocalRecords.txt b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/LocalRecords.txt index 64969a13d3..fbadb01853 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/LocalRecords.txt +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/LocalRecords.txt @@ -61,7 +61,7 @@ | | | | | +- VariableAccess[@AccessType = "READ", @CompileTimeConstant = "false", @Image = "merchants", @Name = "merchants", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | | | +- ArgumentList[@Empty = "true", @Size = "0"] | | | | +- ArgumentList[@Empty = "false", @Size = "1"] - | | | | +- LambdaExpression[@BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] + | | | | +- LambdaExpression[@Arity = "1", @BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | | +- LambdaParameterList[@Empty = "false", @Size = "1"] | | | | | +- LambdaParameter[@EffectiveVisibility = "package", @Final = "false", @TypeInferred = "true", @Visibility = "package"] | | | | | +- ModifierList[@EffectiveModifiers = "{}", @ExplicitModifiers = "{}"] @@ -75,7 +75,7 @@ | | | | +- VariableAccess[@AccessType = "READ", @CompileTimeConstant = "false", @Image = "merchant", @Name = "merchant", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | | +- VariableAccess[@AccessType = "READ", @CompileTimeConstant = "false", @Image = "month", @Name = "month", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | +- ArgumentList[@Empty = "false", @Size = "1"] - | | | +- LambdaExpression[@BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] + | | | +- LambdaExpression[@Arity = "2", @BlockBody = "false", @CompileTimeConstant = "false", @ExpressionBody = "true", @ParenthesisDepth = "0", @Parenthesized = "false"] | | | +- LambdaParameterList[@Empty = "false", @Size = "2"] | | | | +- LambdaParameter[@EffectiveVisibility = "package", @Final = "false", @TypeInferred = "true", @Visibility = "package"] | | | | | +- ModifierList[@EffectiveModifiers = "{}", @ExplicitModifiers = "{}"] From 5cb27503293f816422ac1b422ec2245ee685d22f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 15 Apr 2022 15:05:34 +0200 Subject: [PATCH 061/180] Change task name to 'Processing files' --- .../net/sourceforge/pmd/cli/internal/ProgressBarListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cli/internal/ProgressBarListener.java b/pmd-core/src/main/java/net/sourceforge/pmd/cli/internal/ProgressBarListener.java index 8c27669e79..efdabc3816 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/cli/internal/ProgressBarListener.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/cli/internal/ProgressBarListener.java @@ -29,7 +29,7 @@ public final class ProgressBarListener implements GlobalAnalysisListener { public ProgressBarListener(int totalFiles, Consumer loggingFunction) { progressBar = new ProgressBarBuilder() - .setTaskName("Processing") + .setTaskName("Processing files") .setInitialMax(totalFiles) .setStyle(ProgressBarStyle.ASCII) .continuousUpdate() From 70238044414cd846f6be19a568dc20eaeb793933 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 15 Apr 2022 15:06:53 +0200 Subject: [PATCH 062/180] Inline method to see more clearly what's going on --- .../sourceforge/pmd/cli/internal/ProgressBarListener.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cli/internal/ProgressBarListener.java b/pmd-core/src/main/java/net/sourceforge/pmd/cli/internal/ProgressBarListener.java index efdabc3816..dfb46f197f 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/cli/internal/ProgressBarListener.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/cli/internal/ProgressBarListener.java @@ -38,10 +38,6 @@ public final class ProgressBarListener implements GlobalAnalysisListener { progressBar.setExtraMessage(extraMessage() + "\r"); } - private void incrementProgress() { - progressBar.step(); - refreshProgressBar(); - } /** * Updates progress bar string and forces it to be output regardless of its update interval. @@ -85,7 +81,8 @@ public final class ProgressBarListener implements GlobalAnalysisListener { @Override public void close() { // Refresh progress bar on file analysis end (or file was in cache) - ProgressBarListener.this.incrementProgress(); + progressBar.step(); + refreshProgressBar(); } }; } From 2fee670407db2e27eaca99b737ce805516922838 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 15 Apr 2022 15:08:32 +0200 Subject: [PATCH 063/180] Document default value --- .../src/main/java/net/sourceforge/pmd/PMDConfiguration.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/PMDConfiguration.java b/pmd-core/src/main/java/net/sourceforge/pmd/PMDConfiguration.java index aac28d62c7..0bf7b1b1e9 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/PMDConfiguration.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/PMDConfiguration.java @@ -122,7 +122,7 @@ public class PMDConfiguration extends AbstractConfiguration { private boolean benchmark; private AnalysisCache analysisCache = new NoopAnalysisCache(); private boolean ignoreIncrementalAnalysis; - private boolean progressBar; + private boolean progressBar = false; /** * Get the suppress marker. This is the source level marker used to indicate @@ -793,7 +793,8 @@ public class PMDConfiguration extends AbstractConfiguration { /** - * Returns whether progress bar indicator should be used. + * Returns whether progress bar indicator should be used. The default + * is false. * * @return {@code true} if progress bar indicator is enabled */ From 9620dfc91afb17aa579a5f6cfa257f21a8b8df3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 15 Apr 2022 15:22:40 +0200 Subject: [PATCH 064/180] Update release notes, ref #3866 --- docs/pages/7_0_0_release_notes.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/pages/7_0_0_release_notes.md b/docs/pages/7_0_0_release_notes.md index 51bd0939c6..cc3d9a0dc9 100644 --- a/docs/pages/7_0_0_release_notes.md +++ b/docs/pages/7_0_0_release_notes.md @@ -19,6 +19,15 @@ This is a {{ site.pmd.release_type }} release. ### New and noteworthy +#### CLI improvements + +The PMD CLI has been enhanced with a progress bar, which interactively displays the +current progress of the analysis. + +TODO screenshot (take it right before releasing, because other changes to the CLI will occur until then) + +This can be disabled with the `--no-progress` flag. + #### Full Antlr support Languages backed by an Antlr grammar are now fully supported. This means, it's now possible not only to use Antlr grammars for CPD, @@ -155,7 +164,8 @@ The following previously deprecated rules have been finally removed: * miscellaneous * [#896](https://github.com/pmd/pmd/issues/896): \[all] Use slf4j * [#1451](https://github.com/pmd/pmd/issues/1451): \[core] RulesetFactoryCompatibility stores the whole ruleset file in memory as a string - +* cli + * [#3828](https://github.com/pmd/pmd/issues/3828): \[core] Progress reporting * apex-design * [#2667](https://github.com/pmd/pmd/issues/2667): \[apex] Integrate nawforce/ApexLink to build robust Unused rule * java-bestpractices @@ -279,6 +289,7 @@ The metrics framework has been made simpler and more general. * [#1881](https://github.com/pmd/pmd/pull/1881): \[doc] Add ANTLR documentation - [Matías Fraga](https://github.com/matifraga) * [#1882](https://github.com/pmd/pmd/pull/1882): \[swift] UnavailableFunction Swift rule - [Tomás de Lucca](https://github.com/tomidelucca) * [#2830](https://github.com/pmd/pmd/pull/2830): \[apex] Apexlink POC - [Kevin Jones](https://github.com/nawforce) +* [#3866](https://github.com/pmd/pmd/pull/3866): \[core] Add CLI Progress Bar - [@JerritEic](https://github.com/JerritEic) {% endtocmaker %} From 715442b66b97865782ac31786bcbf73f2a61c0b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 15 Apr 2022 19:31:56 +0200 Subject: [PATCH 065/180] Update java/PMDTaskTest to use mocked rules --- .../net/sourceforge/pmd/ant/PMDTaskTest.java | 35 ++++++------- .../pmd/lang/java/rule/DummyJavaRule.java | 51 +++++++++++++++++++ .../sourceforge/pmd/ant/xml/pmdtasktest.xml | 34 ++++++------- .../rulesets/testing/test-rset-1.xml | 40 +++++++++++++++ .../rulesets/testing/test-rset-2.xml | 25 +++++++++ .../rulesets/testing/test-rset-3.xml | 25 +++++++++ .../pmd/ant/AbstractAntTestHelper.java | 17 ++++--- 7 files changed, 185 insertions(+), 42 deletions(-) create mode 100644 pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/DummyJavaRule.java create mode 100644 pmd-java/src/test/resources/rulesets/testing/test-rset-1.xml create mode 100644 pmd-java/src/test/resources/rulesets/testing/test-rset-2.xml create mode 100644 pmd-java/src/test/resources/rulesets/testing/test-rset-3.xml diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/ant/PMDTaskTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/ant/PMDTaskTest.java index 3cc5d614ce..2ae2b31129 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/ant/PMDTaskTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/ant/PMDTaskTest.java @@ -27,21 +27,20 @@ public class PMDTaskTest extends AbstractAntTestHelper { @Test public void testNoFormattersValidation() { executeTarget("testNoFormattersValidation"); - assertOutputContaining("Fields should be declared at the top of the class"); + assertOutputContaining("Violation from test-rset-1.xml"); } @Test public void testNestedRuleset() { executeTarget("testNestedRuleset"); - assertOutputContaining("Avoid really long methods"); - assertOutputContaining("Fields should be declared at the"); + assertOutputContaining("Violation from test-rset-1.xml"); + assertOutputContaining("Violation from test-rset-2.xml"); } @Test public void testFormatterWithProperties() { executeTarget("testFormatterWithProperties"); - assertOutputContaining("Avoid really long methods"); - assertOutputContaining("Fields should be declared at the"); + assertOutputContaining("Violation from test-rset-1.xml"); assertOutputContaining("link_prefix"); assertOutputContaining("line_prefix"); } @@ -49,42 +48,40 @@ public class PMDTaskTest extends AbstractAntTestHelper { @Test public void testAbstractNames() { executeTarget("testAbstractNames"); - assertOutputContaining("Avoid really long methods"); - assertOutputContaining("Fields should be declared at the"); + assertOutputContaining("Violation from test-rset-1.xml"); + assertOutputContaining("Violation from test-rset-2.xml"); } @Test public void testAbstractNamesInNestedRuleset() { executeTarget("testAbstractNamesInNestedRuleset"); - assertOutputContaining("Avoid really long methods"); - assertOutputContaining("Fields should be declared at the"); + assertOutputContaining("Violation from test-rset-1.xml"); + assertOutputContaining("Violation from test-rset-2.xml"); } @Test public void testCommaInRulesetfiles() { executeTarget("testCommaInRulesetfiles"); - assertOutputContaining("Avoid really long methods"); - assertOutputContaining("Fields should be declared at the"); + assertOutputContaining("Violation from test-rset-1.xml"); + assertOutputContaining("Violation from test-rset-2.xml"); } @Test public void testRelativeRulesets() { executeTarget("testRelativeRulesets"); - assertOutputContaining("Avoid really long methods"); - assertOutputContaining("Fields should be declared at the"); + assertOutputContaining("Violation from test-rset-1.xml"); } @Test public void testRelativeRulesetsInRulesetfiles() { executeTarget("testRelativeRulesetsInRulesetfiles"); - assertOutputContaining("Avoid really long methods"); - assertOutputContaining("Fields should be declared at"); + assertOutputContaining("Violation from test-rset-1.xml"); } @Test public void testExplicitRuleInRuleSet() { executeTarget("testExplicitRuleInRuleSet"); - assertOutputContaining("Avoid really long methods"); + assertOutputContaining("Violation from test-rset-1.xml"); } @Test @@ -166,14 +163,14 @@ public class PMDTaskTest extends AbstractAntTestHelper { @Test public void testMissingCacheLocation() { executeTarget("testMissingCacheLocation"); - assertOutputContaining("Avoid really long methods"); + assertOutputContaining("Violation from test-rset-1.xml"); assertContains(buildRule.getLog(), "This analysis could be faster"); } @Test public void testAnalysisCache() { executeTarget("testAnalysisCache"); - assertOutputContaining("Avoid really long methods"); + assertOutputContaining("Violation from test-rset-1.xml"); assertDoesntContain(buildRule.getLog(), "This analysis could be faster"); assertTrue(currentTempFile().exists()); @@ -183,7 +180,7 @@ public class PMDTaskTest extends AbstractAntTestHelper { @Test public void testDisableIncrementalAnalysis() { executeTarget("testDisableIncrementalAnalysis"); - assertOutputContaining("Avoid really long methods"); + assertOutputContaining("Violation from test-rset-1.xml"); assertDoesntContain(buildRule.getLog(), "This analysis could be faster"); assertFalse(currentTempFile().exists()); diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/DummyJavaRule.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/DummyJavaRule.java new file mode 100644 index 0000000000..a6771bf142 --- /dev/null +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/DummyJavaRule.java @@ -0,0 +1,51 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule; + +import java.util.List; + +import net.sourceforge.pmd.RuleContext; +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; +import net.sourceforge.pmd.lang.java.ast.JavaNode; + +/** + * @author Clément Fournier + */ +public class DummyJavaRule extends AbstractJavaRule { + + @Override + public void apply(List nodes, RuleContext ctx) { + for (Node node : nodes) { + apply(node, ctx); + } + } + + public void apply(Node node, RuleContext ctx) { + + } + + public static class DummyRuleOneViolationPerFile extends DummyJavaRule { + + @Override + public void apply(Node node, RuleContext ctx) { + ctx.addViolation(node); + } + } + + public static class DummyRulePrintsVars extends DummyJavaRule { + + @Override + public void apply(Node node, RuleContext ctx) { + ((JavaNode) node).jjtAccept(this, ctx); + } + + @Override + public Object visit(ASTVariableDeclaratorId node, Object data) { + asCtx(data).addViolation(node, node.getName()); + return super.visit(node, data); + } + } +} diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/ant/xml/pmdtasktest.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/ant/xml/pmdtasktest.xml index 3eedc1b1b2..a1abe53864 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/ant/xml/pmdtasktest.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/ant/xml/pmdtasktest.xml @@ -6,8 +6,8 @@ - ${pmd.home}/src/main/resources/category/java/codestyle.xml - ${pmd.home}/src/main/resources/category/java/design.xml + ${pmd.home}/src/test/resources/rulesets/testing/test-rset-1.xml + ${pmd.home}/src/test/resources/rulesets/testing/test-rset-2.xml @@ -17,8 +17,8 @@ - ${pmd.home}/src/main/resources/category/java/codestyle.xml - ${pmd.home}/src/main/resources/category/java/design.xml + ${pmd.home}/src/test/resources/rulesets/testing/test-rset-1.xml + ${pmd.home}/src/test/resources/rulesets/testing/test-rset-2.xml @@ -30,7 +30,7 @@ - + @@ -40,8 +40,8 @@ - category/java/codestyle.xml - category/java/design.xml + rulesets/testing/test-rset-1.xml + rulesets/testing/test-rset-2.xml @@ -50,7 +50,7 @@ - + @@ -61,7 +61,7 @@ custom_ruleset.xml - category/java/codestyle.xml + rulesets/testing/test-rset-1.xml @@ -70,7 +70,7 @@ - + @@ -79,7 +79,7 @@ - + @@ -87,7 +87,7 @@ - + @@ -111,7 +111,7 @@ - category/java/bestpractices.xml + rulesets/testing/test-rset-3.xml @@ -128,7 +128,7 @@ - category/java/bestpractices.xml + rulesets/testing/test-rset-3.xml + + net.sourceforge.pmd + pmd-jsp + 6.44.0 + + + net.sourceforge.pmd + pmd-javascript + 6.44.0 + net.sourceforge.pmd From 004a59ab04049a08088ba55d74c7b0cf745cb461 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 22 Apr 2022 10:49:13 +0200 Subject: [PATCH 101/180] [html] Add visitor, add tests for xpath and java rules --- .../pmd/lang/html/ast/AbstractHtmlNode.java | 2 +- .../pmd/lang/html/ast/HtmlCDataNode.java | 5 ++ .../pmd/lang/html/ast/HtmlComment.java | 5 ++ .../pmd/lang/html/ast/HtmlDocument.java | 5 ++ .../pmd/lang/html/ast/HtmlDocumentType.java | 5 ++ .../pmd/lang/html/ast/HtmlElement.java | 9 ++ .../pmd/lang/html/ast/HtmlNode.java | 1 + .../pmd/lang/html/ast/HtmlTextNode.java | 5 ++ .../pmd/lang/html/ast/HtmlVisitor.java | 24 +++++ .../pmd/lang/html/ast/HtmlVisitorAdapter.java | 51 +++++++++++ .../pmd/lang/html/ast/HtmlXmlDeclaration.java | 5 ++ .../pmd/lang/html/rule/AbstractHtmlRule.java | 90 +++++++++++++++++++ .../pmd/lang/html/HtmlJavaRuleTest.java | 74 +++++++++++++++ .../pmd/lang/html/HtmlXPathRuleTest.java | 70 +++++++++++++++ 14 files changed, 350 insertions(+), 1 deletion(-) create mode 100644 pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlVisitor.java create mode 100644 pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlVisitorAdapter.java create mode 100644 pmd-html/src/main/java/net/sourceforge/pmd/lang/html/rule/AbstractHtmlRule.java create mode 100644 pmd-html/src/test/java/net/sourceforge/pmd/lang/html/HtmlJavaRuleTest.java create mode 100644 pmd-html/src/test/java/net/sourceforge/pmd/lang/html/HtmlXPathRuleTest.java diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/AbstractHtmlNode.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/AbstractHtmlNode.java index 43741a63ea..53ae8b011c 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/AbstractHtmlNode.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/AbstractHtmlNode.java @@ -9,7 +9,7 @@ import org.jsoup.nodes.Node; import net.sourceforge.pmd.lang.ast.AbstractNode; -class AbstractHtmlNode extends AbstractNode implements HtmlNode { +abstract class AbstractHtmlNode extends AbstractNode implements HtmlNode { protected final T node; diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlCDataNode.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlCDataNode.java index f86402f475..354f99630b 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlCDataNode.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlCDataNode.java @@ -16,4 +16,9 @@ public final class HtmlCDataNode extends AbstractHtmlNode { public String getText() { return node.text(); } + + @Override + public Object acceptVisitor(HtmlVisitor visitor, Object data) { + return visitor.visit(this, data); + } } diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlComment.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlComment.java index 48ffe347e9..671a3dcabd 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlComment.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlComment.java @@ -16,4 +16,9 @@ public final class HtmlComment extends AbstractHtmlNode { public String getData() { return node.getData(); } + + @Override + public Object acceptVisitor(HtmlVisitor visitor, Object data) { + return visitor.visit(this, data); + } } diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlDocument.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlDocument.java index 840166b3d9..05256244ad 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlDocument.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlDocument.java @@ -14,4 +14,9 @@ public class HtmlDocument extends HtmlElement implements RootNode { HtmlDocument(Document document) { super(document); } + + @Override + public Object acceptVisitor(HtmlVisitor visitor, Object data) { + return visitor.visit(this, data); + } } diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlDocumentType.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlDocumentType.java index 3511db323d..6a7e036b29 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlDocumentType.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlDocumentType.java @@ -13,6 +13,11 @@ public final class HtmlDocumentType extends AbstractHtmlNode { super(node); } + @Override + public Object acceptVisitor(HtmlVisitor visitor, Object data) { + return visitor.visit(this, data); + } + public String getName() { return node.name(); } diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlElement.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlElement.java index 6a6c018fa5..505562449e 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlElement.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlElement.java @@ -26,6 +26,15 @@ public class HtmlElement extends AbstractHtmlNode { } } + @Override + public Object acceptVisitor(HtmlVisitor visitor, Object data) { + return visitor.visit(this, data); + } + + public List getAttributes() { + return attributes; + } + @Override public Iterator getXPathAttributesIterator() { Iterator defaultAttributes = super.getXPathAttributesIterator(); diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlNode.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlNode.java index 2cda1e5b38..820229c82b 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlNode.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlNode.java @@ -12,4 +12,5 @@ public interface HtmlNode extends Node { @Override Iterable children(); + Object acceptVisitor(HtmlVisitor visitor, Object data); } diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlTextNode.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlTextNode.java index 16ecb530f1..33430a491e 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlTextNode.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlTextNode.java @@ -13,6 +13,11 @@ public class HtmlTextNode extends AbstractHtmlNode { super(node); } + @Override + public Object acceptVisitor(HtmlVisitor visitor, Object data) { + return visitor.visit(this, data); + } + public String getNormalizedText() { return node.text(); } diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlVisitor.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlVisitor.java new file mode 100644 index 0000000000..67570a3617 --- /dev/null +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlVisitor.java @@ -0,0 +1,24 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.html.ast; + +public interface HtmlVisitor { + + Object visit(HtmlNode node, Object data); + + Object visit(HtmlCDataNode node, Object data); + + Object visit(HtmlComment node, Object data); + + Object visit(HtmlDocument node, Object data); + + Object visit(HtmlDocumentType node, Object data); + + Object visit(HtmlElement node, Object data); + + Object visit(HtmlTextNode node, Object data); + + Object visit(HtmlXmlDeclaration node, Object data); +} diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlVisitorAdapter.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlVisitorAdapter.java new file mode 100644 index 0000000000..09afbec0b4 --- /dev/null +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlVisitorAdapter.java @@ -0,0 +1,51 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.html.ast; + +public class HtmlVisitorAdapter implements HtmlVisitor { + + @Override + public Object visit(HtmlNode node, Object data) { + for (HtmlNode child : node.children()) { + child.acceptVisitor(this, data); + } + return null; + } + + @Override + public Object visit(HtmlCDataNode node, Object data) { + return visit((HtmlNode) node, data); + } + + @Override + public Object visit(HtmlComment node, Object data) { + return visit((HtmlNode) node, data); + } + + @Override + public Object visit(HtmlDocument node, Object data) { + return visit((HtmlNode) node, data); + } + + @Override + public Object visit(HtmlDocumentType node, Object data) { + return visit((HtmlNode) node, data); + } + + @Override + public Object visit(HtmlElement node, Object data) { + return visit((HtmlNode) node, data); + } + + @Override + public Object visit(HtmlTextNode node, Object data) { + return visit((HtmlNode) node, data); + } + + @Override + public Object visit(HtmlXmlDeclaration node, Object data) { + return visit((HtmlNode) node, data); + } +} diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlXmlDeclaration.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlXmlDeclaration.java index 3c80f5cbf2..001751edb3 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlXmlDeclaration.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlXmlDeclaration.java @@ -13,6 +13,11 @@ public final class HtmlXmlDeclaration extends AbstractHtmlNode { super(node); } + @Override + public Object acceptVisitor(HtmlVisitor visitor, Object data) { + return visitor.visit(this, data); + } + public String getName() { return node.name(); } diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/rule/AbstractHtmlRule.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/rule/AbstractHtmlRule.java new file mode 100644 index 0000000000..2dcade1e60 --- /dev/null +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/rule/AbstractHtmlRule.java @@ -0,0 +1,90 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.html.rule; + +import java.util.List; + +import net.sourceforge.pmd.RuleContext; +import net.sourceforge.pmd.lang.LanguageRegistry; +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.html.HtmlLanguageModule; +import net.sourceforge.pmd.lang.html.ast.HtmlCDataNode; +import net.sourceforge.pmd.lang.html.ast.HtmlComment; +import net.sourceforge.pmd.lang.html.ast.HtmlDocument; +import net.sourceforge.pmd.lang.html.ast.HtmlDocumentType; +import net.sourceforge.pmd.lang.html.ast.HtmlElement; +import net.sourceforge.pmd.lang.html.ast.HtmlNode; +import net.sourceforge.pmd.lang.html.ast.HtmlTextNode; +import net.sourceforge.pmd.lang.html.ast.HtmlVisitor; +import net.sourceforge.pmd.lang.html.ast.HtmlXmlDeclaration; +import net.sourceforge.pmd.lang.rule.AbstractRule; + +public abstract class AbstractHtmlRule extends AbstractRule implements HtmlVisitor { + + public AbstractHtmlRule() { + super.setLanguage(LanguageRegistry.getLanguage(HtmlLanguageModule.NAME)); + } + + @Override + public void apply(List nodes, RuleContext ctx) { + for (Node node : nodes) { + if (node instanceof HtmlNode) { + ((HtmlNode) node).acceptVisitor(this, ctx); + } + } + } + + // + // The following APIs are identical to those in HtmlVisitorAdapter. + // Due to Java single inheritance, it is preferred to extend from the more + // complex Rule base class instead of from relatively simple Visitor. + // + // CPD-OFF + + @Override + public Object visit(HtmlNode node, Object data) { + for (HtmlNode child : node.children()) { + child.acceptVisitor(this, data); + } + return null; + } + + @Override + public Object visit(HtmlCDataNode node, Object data) { + return visit((HtmlNode) node, data); + } + + @Override + public Object visit(HtmlComment node, Object data) { + return visit((HtmlNode) node, data); + } + + @Override + public Object visit(HtmlDocument node, Object data) { + return visit((HtmlNode) node, data); + } + + @Override + public Object visit(HtmlDocumentType node, Object data) { + return visit((HtmlNode) node, data); + } + + @Override + public Object visit(HtmlElement node, Object data) { + return visit((HtmlNode) node, data); + } + + @Override + public Object visit(HtmlTextNode node, Object data) { + return visit((HtmlNode) node, data); + } + + @Override + public Object visit(HtmlXmlDeclaration node, Object data) { + return visit((HtmlNode) node, data); + } + + // CPD-ON +} diff --git a/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/HtmlJavaRuleTest.java b/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/HtmlJavaRuleTest.java new file mode 100644 index 0000000000..72af83bfa2 --- /dev/null +++ b/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/HtmlJavaRuleTest.java @@ -0,0 +1,74 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.html; + +import java.io.StringReader; +import java.util.Arrays; + +import org.junit.Assert; +import org.junit.Test; + +import net.sourceforge.pmd.Report; +import net.sourceforge.pmd.Rule; +import net.sourceforge.pmd.RuleContext; +import net.sourceforge.pmd.lang.LanguageRegistry; +import net.sourceforge.pmd.lang.LanguageVersion; +import net.sourceforge.pmd.lang.Parser; +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.ast.xpath.Attribute; +import net.sourceforge.pmd.lang.html.ast.HtmlElement; +import net.sourceforge.pmd.lang.html.rule.AbstractHtmlRule; + +public class HtmlJavaRuleTest { + // from https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.js_props_getter + private static final String LIGHTNING_WEB_COMPONENT = "\n" + + ""; + + @Test + public void findAllAttributesWithInvalidExpression() { + // "Don’t add spaces around the property, for example, { data } is not valid HTML." + Rule rule = new AbstractHtmlRule() { + @Override + public String getMessage() { + return "Invalid expression"; + } + + @Override + public Object visit(HtmlElement node, Object data) { + for (Attribute attribute : node.getAttributes()) { + if ("{".equals(attribute.getValue())) { + RuleContext ctx = (RuleContext) data; + ctx.addViolation(node); + } + } + return super.visit(node, data); + } + }; + Report report = runRule(LIGHTNING_WEB_COMPONENT, rule); + Assert.assertEquals(2, report.getViolations().size()); + Assert.assertEquals(4, report.getViolations().get(0).getBeginLine()); + Assert.assertEquals(6, report.getViolations().get(1).getBeginLine()); + } + + private Report runRule(String html, Rule rule) { + LanguageVersion htmlLanguage = LanguageRegistry.findLanguageByTerseName(HtmlLanguageModule.TERSE_NAME).getDefaultVersion(); + Parser parser = htmlLanguage.getLanguageVersionHandler().getParser(htmlLanguage.getLanguageVersionHandler().getDefaultParserOptions()); + + Node node = parser.parse("n/a", new StringReader(html)); + RuleContext context = new RuleContext(); + context.setLanguageVersion(htmlLanguage); + context.setCurrentRule(rule); + rule.apply(Arrays.asList(node), context); + return context.getReport(); + } +} diff --git a/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/HtmlXPathRuleTest.java b/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/HtmlXPathRuleTest.java new file mode 100644 index 0000000000..6c2c53e2f9 --- /dev/null +++ b/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/HtmlXPathRuleTest.java @@ -0,0 +1,70 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.html; + +import java.io.StringReader; +import java.util.Arrays; + +import org.junit.Assert; +import org.junit.Test; + +import net.sourceforge.pmd.Report; +import net.sourceforge.pmd.RuleContext; +import net.sourceforge.pmd.lang.LanguageRegistry; +import net.sourceforge.pmd.lang.LanguageVersion; +import net.sourceforge.pmd.lang.Parser; +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.rule.XPathRule; +import net.sourceforge.pmd.lang.rule.xpath.XPathVersion; + +public class HtmlXPathRuleTest { + // from https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.js_props_getter + private static final String LIGHTNING_WEB_COMPONENT = "\n" + + ""; + + @Test + public void selectTextNode() { + // from https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.js_props_getter + // "Don’t add spaces around the property, for example, { data } is not valid HTML." + String xpath = "//*[local-name() = '#text'][contains(@Text, '{ ')]"; + + Report report = runXPath(LIGHTNING_WEB_COMPONENT, xpath); + Assert.assertEquals(1, report.getViolations().size()); + Assert.assertEquals(3, report.getViolations().get(0).getBeginLine()); + } + + @Test + public void selectAttributes() { + // from https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.js_props_getter + // "Don’t add spaces around the property, for example, { data } is not valid HTML." + String xpath = "//*[@value = '{']"; + + Report report = runXPath(LIGHTNING_WEB_COMPONENT, xpath); + Assert.assertEquals(1, report.getViolations().size()); + Assert.assertEquals(4, report.getViolations().get(0).getBeginLine()); + } + + private Report runXPath(String html, String xpath) { + LanguageVersion htmlLanguage = LanguageRegistry.findLanguageByTerseName(HtmlLanguageModule.TERSE_NAME).getDefaultVersion(); + Parser parser = htmlLanguage.getLanguageVersionHandler().getParser(htmlLanguage.getLanguageVersionHandler().getDefaultParserOptions()); + + XPathRule rule = new XPathRule(XPathVersion.XPATH_2_0, xpath); + rule.setMessage("test"); + Node node = parser.parse("n/a", new StringReader(html)); + RuleContext context = new RuleContext(); + context.setLanguageVersion(htmlLanguage); + context.setCurrentRule(rule); + rule.apply(Arrays.asList(node), context); + return context.getReport(); + } +} From 3e8274fd0d8bef76c34fbd4c943de5d4e8c48a94 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 22 Apr 2022 11:32:50 +0200 Subject: [PATCH 102/180] [html] Rename AST nodes --- .../pmd/lang/html/HtmlTokenizer.java | 10 ++--- ...mlCDataNode.java => ASTHtmlCDataNode.java} | 4 +- .../{HtmlComment.java => ASTHtmlComment.java} | 4 +- ...HtmlDocument.java => ASTHtmlDocument.java} | 4 +- ...mentType.java => ASTHtmlDocumentType.java} | 4 +- .../{HtmlElement.java => ASTHtmlElement.java} | 4 +- ...HtmlTextNode.java => ASTHtmlTextNode.java} | 4 +- ...ration.java => ASTHtmlXmlDeclaration.java} | 4 +- .../pmd/lang/html/ast/HtmlTreeBuilder.java | 16 ++++---- .../pmd/lang/html/ast/HtmlVisitor.java | 14 +++---- .../pmd/lang/html/ast/HtmlVisitorAdapter.java | 14 +++---- .../pmd/lang/html/ast/LineNumbers.java | 40 +++++++++---------- .../pmd/lang/html/rule/AbstractHtmlRule.java | 28 ++++++------- .../pmd/lang/html/HtmlJavaRuleTest.java | 4 +- .../pmd/lang/html/ast/HtmlParsingHelper.java | 4 +- .../pmd/lang/html/ast/HtmlTreeDumpTest.java | 2 +- .../pmd/lang/html/ast/PositionTest.java | 2 +- 17 files changed, 81 insertions(+), 81 deletions(-) rename pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/{HtmlCDataNode.java => ASTHtmlCDataNode.java} (77%) rename pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/{HtmlComment.java => ASTHtmlComment.java} (79%) rename pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/{HtmlDocument.java => ASTHtmlDocument.java} (76%) rename pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/{HtmlDocumentType.java => ASTHtmlDocumentType.java} (81%) rename pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/{HtmlElement.java => ASTHtmlElement.java} (93%) rename pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/{HtmlTextNode.java => ASTHtmlTextNode.java} (84%) rename pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/{HtmlXmlDeclaration.java => ASTHtmlXmlDeclaration.java} (75%) diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/HtmlTokenizer.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/HtmlTokenizer.java index ad803faade..2804a39a62 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/HtmlTokenizer.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/HtmlTokenizer.java @@ -14,9 +14,9 @@ import net.sourceforge.pmd.cpd.SourceCode; import net.sourceforge.pmd.cpd.TokenEntry; import net.sourceforge.pmd.cpd.Tokenizer; import net.sourceforge.pmd.cpd.Tokens; -import net.sourceforge.pmd.lang.html.ast.HtmlDocument; +import net.sourceforge.pmd.lang.html.ast.ASTHtmlDocument; +import net.sourceforge.pmd.lang.html.ast.ASTHtmlTextNode; import net.sourceforge.pmd.lang.html.ast.HtmlNode; -import net.sourceforge.pmd.lang.html.ast.HtmlTextNode; import net.sourceforge.pmd.lang.html.ast.HtmlTreeBuilder; class HtmlTokenizer implements Tokenizer { @@ -27,7 +27,7 @@ class HtmlTokenizer implements Tokenizer { Document doc = Parser.xmlParser().parseInput(data, ""); HtmlTreeBuilder builder = new HtmlTreeBuilder(); - HtmlDocument root = builder.build(doc, data); + ASTHtmlDocument root = builder.build(doc, data); traverse(root, tokenEntries); tokenEntries.add(TokenEntry.EOF); @@ -36,8 +36,8 @@ class HtmlTokenizer implements Tokenizer { private void traverse(HtmlNode node, Tokens tokenEntries) { String image = node.getXPathNodeName(); - if (node instanceof HtmlTextNode) { - image = ((HtmlTextNode) node).getText(); + if (node instanceof ASTHtmlTextNode) { + image = ((ASTHtmlTextNode) node).getText(); } TokenEntry token = new TokenEntry(image, node.getXPathNodeName(), node.getBeginLine(), diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlCDataNode.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlCDataNode.java similarity index 77% rename from pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlCDataNode.java rename to pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlCDataNode.java index 354f99630b..1074e740e8 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlCDataNode.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlCDataNode.java @@ -7,9 +7,9 @@ package net.sourceforge.pmd.lang.html.ast; import org.jsoup.nodes.CDataNode; -public final class HtmlCDataNode extends AbstractHtmlNode { +public final class ASTHtmlCDataNode extends AbstractHtmlNode { - HtmlCDataNode(CDataNode node) { + ASTHtmlCDataNode(CDataNode node) { super(node); } diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlComment.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlComment.java similarity index 79% rename from pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlComment.java rename to pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlComment.java index 671a3dcabd..b00053fc90 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlComment.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlComment.java @@ -7,9 +7,9 @@ package net.sourceforge.pmd.lang.html.ast; import org.jsoup.nodes.Comment; -public final class HtmlComment extends AbstractHtmlNode { +public final class ASTHtmlComment extends AbstractHtmlNode { - HtmlComment(Comment node) { + ASTHtmlComment(Comment node) { super(node); } diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlDocument.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlDocument.java similarity index 76% rename from pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlDocument.java rename to pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlDocument.java index 05256244ad..b429e463c6 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlDocument.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlDocument.java @@ -9,9 +9,9 @@ import org.jsoup.nodes.Document; import net.sourceforge.pmd.lang.ast.RootNode; -public class HtmlDocument extends HtmlElement implements RootNode { +public class ASTHtmlDocument extends ASTHtmlElement implements RootNode { - HtmlDocument(Document document) { + ASTHtmlDocument(Document document) { super(document); } diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlDocumentType.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlDocumentType.java similarity index 81% rename from pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlDocumentType.java rename to pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlDocumentType.java index 6a7e036b29..0345fa1fc1 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlDocumentType.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlDocumentType.java @@ -7,9 +7,9 @@ package net.sourceforge.pmd.lang.html.ast; import org.jsoup.nodes.DocumentType; -public final class HtmlDocumentType extends AbstractHtmlNode { +public final class ASTHtmlDocumentType extends AbstractHtmlNode { - HtmlDocumentType(DocumentType node) { + ASTHtmlDocumentType(DocumentType node) { super(node); } diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlElement.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlElement.java similarity index 93% rename from pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlElement.java rename to pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlElement.java index 505562449e..fe01917db9 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlElement.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlElement.java @@ -13,11 +13,11 @@ import org.jsoup.nodes.Element; import net.sourceforge.pmd.lang.ast.xpath.Attribute; -public class HtmlElement extends AbstractHtmlNode { +public class ASTHtmlElement extends AbstractHtmlNode { private final List attributes; - HtmlElement(Element element) { + ASTHtmlElement(Element element) { super(element); attributes = new ArrayList<>(); diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlTextNode.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlTextNode.java similarity index 84% rename from pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlTextNode.java rename to pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlTextNode.java index 33430a491e..1f7d7ef07d 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlTextNode.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlTextNode.java @@ -7,9 +7,9 @@ package net.sourceforge.pmd.lang.html.ast; import org.jsoup.nodes.TextNode; -public class HtmlTextNode extends AbstractHtmlNode { +public class ASTHtmlTextNode extends AbstractHtmlNode { - HtmlTextNode(TextNode node) { + ASTHtmlTextNode(TextNode node) { super(node); } diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlXmlDeclaration.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlXmlDeclaration.java similarity index 75% rename from pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlXmlDeclaration.java rename to pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlXmlDeclaration.java index 001751edb3..87a1ef17ea 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlXmlDeclaration.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlXmlDeclaration.java @@ -7,9 +7,9 @@ package net.sourceforge.pmd.lang.html.ast; import org.jsoup.nodes.XmlDeclaration; -public final class HtmlXmlDeclaration extends AbstractHtmlNode { +public final class ASTHtmlXmlDeclaration extends AbstractHtmlNode { - HtmlXmlDeclaration(XmlDeclaration node) { + ASTHtmlXmlDeclaration(XmlDeclaration node) { super(node); } diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlTreeBuilder.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlTreeBuilder.java index f9f72eb8cf..795dcda1a7 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlTreeBuilder.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlTreeBuilder.java @@ -19,8 +19,8 @@ import net.sourceforge.pmd.annotation.InternalApi; @InternalApi public final class HtmlTreeBuilder { - public HtmlDocument build(Document doc, String htmlString) { - HtmlDocument root = new HtmlDocument(doc); + public ASTHtmlDocument build(Document doc, String htmlString) { + ASTHtmlDocument root = new ASTHtmlDocument(doc); addChilds(root, doc); LineNumbers lineNumbers = new LineNumbers(root, htmlString); @@ -39,17 +39,17 @@ public final class HtmlTreeBuilder { private HtmlNode convertJsoupNode(Node node) { if (node instanceof Element) { - return new HtmlElement((Element) node); + return new ASTHtmlElement((Element) node); } else if (node instanceof CDataNode) { - return new HtmlCDataNode((CDataNode) node); + return new ASTHtmlCDataNode((CDataNode) node); } else if (node instanceof TextNode) { - return new HtmlTextNode((TextNode) node); + return new ASTHtmlTextNode((TextNode) node); } else if (node instanceof Comment) { - return new HtmlComment((Comment) node); + return new ASTHtmlComment((Comment) node); } else if (node instanceof XmlDeclaration) { - return new HtmlXmlDeclaration((XmlDeclaration) node); + return new ASTHtmlXmlDeclaration((XmlDeclaration) node); } else if (node instanceof DocumentType) { - return new HtmlDocumentType((DocumentType) node); + return new ASTHtmlDocumentType((DocumentType) node); } else { throw new RuntimeException("Unsupported node type: " + node.getClass()); } diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlVisitor.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlVisitor.java index 67570a3617..143488ccfc 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlVisitor.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlVisitor.java @@ -8,17 +8,17 @@ public interface HtmlVisitor { Object visit(HtmlNode node, Object data); - Object visit(HtmlCDataNode node, Object data); + Object visit(ASTHtmlCDataNode node, Object data); - Object visit(HtmlComment node, Object data); + Object visit(ASTHtmlComment node, Object data); - Object visit(HtmlDocument node, Object data); + Object visit(ASTHtmlDocument node, Object data); - Object visit(HtmlDocumentType node, Object data); + Object visit(ASTHtmlDocumentType node, Object data); - Object visit(HtmlElement node, Object data); + Object visit(ASTHtmlElement node, Object data); - Object visit(HtmlTextNode node, Object data); + Object visit(ASTHtmlTextNode node, Object data); - Object visit(HtmlXmlDeclaration node, Object data); + Object visit(ASTHtmlXmlDeclaration node, Object data); } diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlVisitorAdapter.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlVisitorAdapter.java index 09afbec0b4..8907439e48 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlVisitorAdapter.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlVisitorAdapter.java @@ -15,37 +15,37 @@ public class HtmlVisitorAdapter implements HtmlVisitor { } @Override - public Object visit(HtmlCDataNode node, Object data) { + public Object visit(ASTHtmlCDataNode node, Object data) { return visit((HtmlNode) node, data); } @Override - public Object visit(HtmlComment node, Object data) { + public Object visit(ASTHtmlComment node, Object data) { return visit((HtmlNode) node, data); } @Override - public Object visit(HtmlDocument node, Object data) { + public Object visit(ASTHtmlDocument node, Object data) { return visit((HtmlNode) node, data); } @Override - public Object visit(HtmlDocumentType node, Object data) { + public Object visit(ASTHtmlDocumentType node, Object data) { return visit((HtmlNode) node, data); } @Override - public Object visit(HtmlElement node, Object data) { + public Object visit(ASTHtmlElement node, Object data) { return visit((HtmlNode) node, data); } @Override - public Object visit(HtmlTextNode node, Object data) { + public Object visit(ASTHtmlTextNode node, Object data) { return visit((HtmlNode) node, data); } @Override - public Object visit(HtmlXmlDeclaration node, Object data) { + public Object visit(ASTHtmlXmlDeclaration node, Object data) { return visit((HtmlNode) node, data); } } diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/LineNumbers.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/LineNumbers.java index 52b9a2904d..11d3517353 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/LineNumbers.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/LineNumbers.java @@ -7,11 +7,11 @@ package net.sourceforge.pmd.lang.html.ast; import net.sourceforge.pmd.lang.ast.SourceCodePositioner; class LineNumbers { - private final HtmlDocument document; + private final ASTHtmlDocument document; private String htmlString; private SourceCodePositioner sourceCodePositioner; - LineNumbers(HtmlDocument document, String htmlString) { + LineNumbers(ASTHtmlDocument document, String htmlString) { this.document = document; this.htmlString = htmlString; this.sourceCodePositioner = new SourceCodePositioner(htmlString); @@ -26,20 +26,20 @@ class LineNumbers { int nodeLength = 0; int textLength = 0; - if (n instanceof HtmlDocument) { + if (n instanceof ASTHtmlDocument) { nextIndex = index; - } else if (n instanceof HtmlComment) { + } else if (n instanceof ASTHtmlComment) { nextIndex = htmlString.indexOf(" - nextIndex += ((HtmlComment) n).getData().length(); - } else if (n instanceof HtmlTextNode) { + nextIndex += ((ASTHtmlComment) n).getData().length(); + } else if (n instanceof ASTHtmlTextNode) { nextIndex += textLength; - } else if (n instanceof HtmlCDataNode) { - nextIndex += "".length(); - } else if (n instanceof HtmlXmlDeclaration) { + } else if (n instanceof ASTHtmlCDataNode) { + nextIndex += "".length(); + } else if (n instanceof ASTHtmlXmlDeclaration) { nextIndex = htmlString.indexOf("?>", nextIndex) + 2; - } else if (n instanceof HtmlDocumentType) { + } else if (n instanceof ASTHtmlDocumentType) { nextIndex = htmlString.indexOf(">", nextIndex) + 1; } diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/rule/AbstractHtmlRule.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/rule/AbstractHtmlRule.java index 2dcade1e60..c65e21d7e8 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/rule/AbstractHtmlRule.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/rule/AbstractHtmlRule.java @@ -10,15 +10,15 @@ import net.sourceforge.pmd.RuleContext; import net.sourceforge.pmd.lang.LanguageRegistry; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.html.HtmlLanguageModule; -import net.sourceforge.pmd.lang.html.ast.HtmlCDataNode; -import net.sourceforge.pmd.lang.html.ast.HtmlComment; -import net.sourceforge.pmd.lang.html.ast.HtmlDocument; -import net.sourceforge.pmd.lang.html.ast.HtmlDocumentType; -import net.sourceforge.pmd.lang.html.ast.HtmlElement; +import net.sourceforge.pmd.lang.html.ast.ASTHtmlCDataNode; +import net.sourceforge.pmd.lang.html.ast.ASTHtmlComment; +import net.sourceforge.pmd.lang.html.ast.ASTHtmlDocument; +import net.sourceforge.pmd.lang.html.ast.ASTHtmlDocumentType; +import net.sourceforge.pmd.lang.html.ast.ASTHtmlElement; +import net.sourceforge.pmd.lang.html.ast.ASTHtmlTextNode; +import net.sourceforge.pmd.lang.html.ast.ASTHtmlXmlDeclaration; import net.sourceforge.pmd.lang.html.ast.HtmlNode; -import net.sourceforge.pmd.lang.html.ast.HtmlTextNode; import net.sourceforge.pmd.lang.html.ast.HtmlVisitor; -import net.sourceforge.pmd.lang.html.ast.HtmlXmlDeclaration; import net.sourceforge.pmd.lang.rule.AbstractRule; public abstract class AbstractHtmlRule extends AbstractRule implements HtmlVisitor { @@ -52,37 +52,37 @@ public abstract class AbstractHtmlRule extends AbstractRule implements HtmlVisit } @Override - public Object visit(HtmlCDataNode node, Object data) { + public Object visit(ASTHtmlCDataNode node, Object data) { return visit((HtmlNode) node, data); } @Override - public Object visit(HtmlComment node, Object data) { + public Object visit(ASTHtmlComment node, Object data) { return visit((HtmlNode) node, data); } @Override - public Object visit(HtmlDocument node, Object data) { + public Object visit(ASTHtmlDocument node, Object data) { return visit((HtmlNode) node, data); } @Override - public Object visit(HtmlDocumentType node, Object data) { + public Object visit(ASTHtmlDocumentType node, Object data) { return visit((HtmlNode) node, data); } @Override - public Object visit(HtmlElement node, Object data) { + public Object visit(ASTHtmlElement node, Object data) { return visit((HtmlNode) node, data); } @Override - public Object visit(HtmlTextNode node, Object data) { + public Object visit(ASTHtmlTextNode node, Object data) { return visit((HtmlNode) node, data); } @Override - public Object visit(HtmlXmlDeclaration node, Object data) { + public Object visit(ASTHtmlXmlDeclaration node, Object data) { return visit((HtmlNode) node, data); } diff --git a/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/HtmlJavaRuleTest.java b/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/HtmlJavaRuleTest.java index 72af83bfa2..307a7aef74 100644 --- a/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/HtmlJavaRuleTest.java +++ b/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/HtmlJavaRuleTest.java @@ -18,7 +18,7 @@ import net.sourceforge.pmd.lang.LanguageVersion; import net.sourceforge.pmd.lang.Parser; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.ast.xpath.Attribute; -import net.sourceforge.pmd.lang.html.ast.HtmlElement; +import net.sourceforge.pmd.lang.html.ast.ASTHtmlElement; import net.sourceforge.pmd.lang.html.rule.AbstractHtmlRule; public class HtmlJavaRuleTest { @@ -44,7 +44,7 @@ public class HtmlJavaRuleTest { } @Override - public Object visit(HtmlElement node, Object data) { + public Object visit(ASTHtmlElement node, Object data) { for (Attribute attribute : node.getAttributes()) { if ("{".equals(attribute.getValue())) { RuleContext ctx = (RuleContext) data; diff --git a/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/ast/HtmlParsingHelper.java b/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/ast/HtmlParsingHelper.java index 7cdcc057f9..37812e7f1c 100644 --- a/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/ast/HtmlParsingHelper.java +++ b/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/ast/HtmlParsingHelper.java @@ -7,12 +7,12 @@ package net.sourceforge.pmd.lang.html.ast; import net.sourceforge.pmd.lang.ast.test.BaseParsingHelper; import net.sourceforge.pmd.lang.html.HtmlLanguageModule; -public final class HtmlParsingHelper extends BaseParsingHelper { +public final class HtmlParsingHelper extends BaseParsingHelper { public static final HtmlParsingHelper DEFAULT = new HtmlParsingHelper(Params.getDefaultProcess()); private HtmlParsingHelper(Params params) { - super(HtmlLanguageModule.NAME, HtmlDocument.class, params); + super(HtmlLanguageModule.NAME, ASTHtmlDocument.class, params); } @Override diff --git a/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/ast/HtmlTreeDumpTest.java b/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/ast/HtmlTreeDumpTest.java index 8ffe75d03a..05f83eb600 100644 --- a/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/ast/HtmlTreeDumpTest.java +++ b/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/ast/HtmlTreeDumpTest.java @@ -17,7 +17,7 @@ public class HtmlTreeDumpTest extends BaseTreeDumpTest { } @Override - public BaseParsingHelper getParser() { + public BaseParsingHelper getParser() { return HtmlParsingHelper.DEFAULT.withResourceContext(HtmlTreeDumpTest.class, "testdata"); } diff --git a/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/ast/PositionTest.java b/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/ast/PositionTest.java index aa7db3ddb0..37b7d21322 100644 --- a/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/ast/PositionTest.java +++ b/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/ast/PositionTest.java @@ -22,7 +22,7 @@ public class PositionTest extends BaseTreeDumpTest { } @Override - public BaseParsingHelper getParser() { + public BaseParsingHelper getParser() { return HtmlParsingHelper.DEFAULT.withResourceContext(HtmlTreeDumpTest.class, "testdata"); } From b3871a14761237a7755129bbe0609d446d7e2388 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 22 Apr 2022 11:39:38 +0200 Subject: [PATCH 103/180] [html] New rule UnnecessaryTypeAttributeRule --- .../pmd/lang/html/ast/AbstractHtmlNode.java | 4 + .../UnnecessaryTypeAttributeRule.java | 50 ++++++ .../resources/category/html/bestpractices.xml | 24 +++ .../UnnecessaryTypeAttributeTest.java | 11 ++ .../lang/html/ast/testdata/SimpleHtmlFile.txt | 30 ++-- .../lang/html/ast/testdata/SimpleXmlFile.txt | 18 +- .../html/ast/testdata/TemplateFragment.txt | 166 +++++++++--------- .../xml/UnnecessaryTypeAttribute.xml | 37 ++++ 8 files changed, 233 insertions(+), 107 deletions(-) create mode 100644 pmd-html/src/main/java/net/sourceforge/pmd/lang/html/rule/bestpractices/UnnecessaryTypeAttributeRule.java create mode 100644 pmd-html/src/test/java/net/sourceforge/pmd/lang/html/rule/bestpractices/UnnecessaryTypeAttributeTest.java create mode 100644 pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/rule/bestpractices/xml/UnnecessaryTypeAttribute.xml diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/AbstractHtmlNode.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/AbstractHtmlNode.java index 53ae8b011c..6517233002 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/AbstractHtmlNode.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/AbstractHtmlNode.java @@ -18,6 +18,10 @@ abstract class AbstractHtmlNode extends AbstractNode implements this.node = node; } + public String getNodeName() { + return node.nodeName(); + } + @Override public String getXPathNodeName() { return node.nodeName(); diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/rule/bestpractices/UnnecessaryTypeAttributeRule.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/rule/bestpractices/UnnecessaryTypeAttributeRule.java new file mode 100644 index 0000000000..49f230e92a --- /dev/null +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/rule/bestpractices/UnnecessaryTypeAttributeRule.java @@ -0,0 +1,50 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.html.rule.bestpractices; + +import net.sourceforge.pmd.RuleContext; +import net.sourceforge.pmd.lang.ast.xpath.Attribute; +import net.sourceforge.pmd.lang.html.ast.ASTHtmlElement; +import net.sourceforge.pmd.lang.html.rule.AbstractHtmlRule; + +public class UnnecessaryTypeAttributeRule extends AbstractHtmlRule { + + @Override + public Object visit(ASTHtmlElement node, Object data) { + if ("link".equalsIgnoreCase(node.getNodeName())) { + checkLink(node, data); + } else if ("script".equalsIgnoreCase(node.getNodeName())) { + checkScript(node, data); + } + return super.visit(node, data); + } + + private void checkScript(ASTHtmlElement node, Object data) { + if (getAttribute(node, "type") != null) { + addViolation(node, data); + } + } + + private void checkLink(ASTHtmlElement node, Object data) { + String rel = getAttribute(node, "rel"); + if (getAttribute(node, "type") != null && "stylesheet".equalsIgnoreCase(rel)) { + addViolation(node, data); + } + } + + private String getAttribute(ASTHtmlElement node, String rel) { + return node.getAttributes().stream() + .filter(attribute -> rel.equalsIgnoreCase(attribute.getName())) + .findFirst() + .map(Attribute::getValue) + .map(String::valueOf) + .orElse(null); + } + + private void addViolation(ASTHtmlElement node, Object data) { + RuleContext ctx = (RuleContext) data; + ctx.addViolation(node); + } +} diff --git a/pmd-html/src/main/resources/category/html/bestpractices.xml b/pmd-html/src/main/resources/category/html/bestpractices.xml index d64ee57961..565fe30da2 100644 --- a/pmd-html/src/main/resources/category/html/bestpractices.xml +++ b/pmd-html/src/main/resources/category/html/bestpractices.xml @@ -33,6 +33,30 @@ This helps to reuse common styles. +]]> + + + + + + In HTML5 the explicit type attribute for link and script elements is not needed. Modern browsers expect + stylesheets to be in CSS and scripts to use JavaScript. + + 3 + + + + + + + + ]]> diff --git a/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/rule/bestpractices/UnnecessaryTypeAttributeTest.java b/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/rule/bestpractices/UnnecessaryTypeAttributeTest.java new file mode 100644 index 0000000000..b955463364 --- /dev/null +++ b/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/rule/bestpractices/UnnecessaryTypeAttributeTest.java @@ -0,0 +1,11 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.html.rule.bestpractices; + +import net.sourceforge.pmd.testframework.PmdRuleTst; + +public class UnnecessaryTypeAttributeTest extends PmdRuleTst { + // no additional unit tests +} diff --git a/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/ast/testdata/SimpleHtmlFile.txt b/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/ast/testdata/SimpleHtmlFile.txt index 3dbe45de94..058a83898d 100644 --- a/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/ast/testdata/SimpleHtmlFile.txt +++ b/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/ast/testdata/SimpleHtmlFile.txt @@ -1,22 +1,22 @@ -+- #document[] - +- #doctype[@Name = "html", @PublicId = "", @SystemId = ""] - +- #text[@Image = " ", @NormalizedText = " ", @Text = " ++- #document[@NodeName = "#document"] + +- #doctype[@Name = "html", @NodeName = "#doctype", @PublicId = "", @SystemId = ""] + +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - +- html[] - | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + +- html[@NodeName = "html"] + | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | +- head[] - | | +- #text[@Image = "hello", @NormalizedText = "hello", @Text = "hello"] - | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | +- head[@NodeName = "head"] + | | +- #text[@Image = "hello", @NodeName = "#text", @NormalizedText = "hello", @Text = "hello"] + | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | +- body[] - | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | +- body[@NodeName = "body"] + | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | | +- h1[] - | | | +- #text[@Image = "world", @NormalizedText = "world", @Text = "world"] - | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | | +- h1[@NodeName = "h1"] + | | | +- #text[@Image = "world", @NodeName = "#text", @NormalizedText = "world", @Text = "world"] + | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - +- #text[@Image = " ", @NormalizedText = " ", @Text = " + +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] diff --git a/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/ast/testdata/SimpleXmlFile.txt b/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/ast/testdata/SimpleXmlFile.txt index 29a2088979..a5c715bfb0 100644 --- a/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/ast/testdata/SimpleXmlFile.txt +++ b/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/ast/testdata/SimpleXmlFile.txt @@ -1,13 +1,13 @@ -+- #document[] - +- #declaration[@Name = "xml"] - +- #text[@Image = " ", @NormalizedText = " ", @Text = " ++- #document[@NodeName = "#document"] + +- #declaration[@Name = "xml", @NodeName = "#declaration"] + +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - +- root[] - | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + +- root[@NodeName = "root"] + | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | +- child[@attr1 = "value1"] - | | +- #text[@Image = "text & entities", @NormalizedText = "text & entities", @Text = "text & entities"] - | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | +- child[@NodeName = "child", @attr1 = "value1"] + | | +- #text[@Image = "text & entities", @NodeName = "#text", @NormalizedText = "text & entities", @Text = "text & entities"] + | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - +- #text[@Image = " ", @NormalizedText = " ", @Text = " + +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] diff --git a/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/ast/testdata/TemplateFragment.txt b/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/ast/testdata/TemplateFragment.txt index db08ecb82d..c9e048e3be 100644 --- a/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/ast/testdata/TemplateFragment.txt +++ b/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/ast/testdata/TemplateFragment.txt @@ -1,130 +1,130 @@ -+- #document[] - +- #comment[@Data = " from https://raw.githubusercontent.com/trailheadapps/lwc-recipes-oss/main/src/modules/ui/app/app.html "] - +- #text[@Image = " ", @NormalizedText = " ", @Text = " ++- #document[@NodeName = "#document"] + +- #comment[@Data = " from https://raw.githubusercontent.com/trailheadapps/lwc-recipes-oss/main/src/modules/ui/app/app.html ", @NodeName = "#comment"] + +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - +- template[] - | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + +- template[@NodeName = "template"] + | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | +- section[@class = "content container page-background"] - | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | +- section[@NodeName = "section", @class = "content container page-background"] + | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | | +- ui-navbar[@nav-items = "{navigationItems}", @oncategorychange = "{handleCategoryChange}", @selected-item = "{currentNavigationItem}"] - | | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | | +- ui-navbar[@NodeName = "ui-navbar", @nav-items = "{navigationItems}", @oncategorychange = "{handleCategoryChange}", @selected-item = "{currentNavigationItem}"] + | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | | +- article[@class = "container"] - | | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | | +- article[@NodeName = "article", @class = "container"] + | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | | | +- div[] - | | | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | | | +- div[@NodeName = "div"] + | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | | | | +- template[@if:true = "{navigationItems.hello.visible}"] - | | | | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | | | | +- template[@NodeName = "template", @if:true = "{navigationItems.hello.visible}"] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | | | | | +- recipe-hello[] - | | | | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | | | | | +- recipe-hello[@NodeName = "recipe-hello"] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | | | | | +- recipe-hello-binding[] - | | | | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | | | | | +- recipe-hello-binding[@NodeName = "recipe-hello-binding"] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | | | | | +- recipe-hello-expressions[] - | | | | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | | | | | +- recipe-hello-expressions[@NodeName = "recipe-hello-expressions"] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | | | | | +- recipe-hello-expressions-track[] - | | | | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | | | | | +- recipe-hello-expressions-track[@NodeName = "recipe-hello-expressions-track"] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | | | | | +- recipe-hello-conditional-rendering[] - | | | | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | | | | | +- recipe-hello-conditional-rendering[@NodeName = "recipe-hello-conditional-rendering"] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | | | | | +- recipe-hello-for-each[] - | | | | | +- recipe-hello-iterator[] - | | | | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | | | | | +- recipe-hello-for-each[@NodeName = "recipe-hello-for-each"] + | | | | | +- recipe-hello-iterator[@NodeName = "recipe-hello-iterator"] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | | | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | | | | +- template[@if:true = "{navigationItems.composition.visible}"] - | | | | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | | | | +- template[@NodeName = "template", @if:true = "{navigationItems.composition.visible}"] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | | | | | +- recipe-composition-basics[] - | | | | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | | | | | +- recipe-composition-basics[@NodeName = "recipe-composition-basics"] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | | | | | +- recipe-composition-iteration[] - | | | | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | | | | | +- recipe-composition-iteration[@NodeName = "recipe-composition-iteration"] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | | | | | +- recipe-composition-contact-search[] - | | | | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | | | | | +- recipe-composition-contact-search[@NodeName = "recipe-composition-contact-search"] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | | | | | +- recipe-composition-dynamic[] - | | | | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | | | | | +- recipe-composition-dynamic[@NodeName = "recipe-composition-dynamic"] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | | | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | | | | +- template[@if:true = "{navigationItems.child.visible}"] - | | | | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | | | | +- template[@NodeName = "template", @if:true = "{navigationItems.child.visible}"] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | | | | | +- recipe-event-simple[] - | | | | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | | | | | +- recipe-event-simple[@NodeName = "recipe-event-simple"] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | | | | | +- recipe-event-with-data[] - | | | | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | | | | | +- recipe-event-with-data[@NodeName = "recipe-event-with-data"] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | | | | | +- recipe-event-bubbling[] - | | | | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | | | | | +- recipe-event-bubbling[@NodeName = "recipe-event-bubbling"] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | | | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | | | | +- template[@if:true = "{navigationItems.parent.visible}"] - | | | | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | | | | +- template[@NodeName = "template", @if:true = "{navigationItems.parent.visible}"] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | | | | | +- recipe-api-property[] - | | | | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | | | | | +- recipe-api-property[@NodeName = "recipe-api-property"] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | | | | | +- recipe-api-function[] - | | | | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | | | | | +- recipe-api-function[@NodeName = "recipe-api-function"] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | | | | | +- recipe-api-setter-getter[] - | | | | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | | | | | +- recipe-api-setter-getter[@NodeName = "recipe-api-setter-getter"] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | | | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | | | | +- template[@if:true = "{navigationItems.misc.visible}"] - | | | | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | | | | +- template[@NodeName = "template", @if:true = "{navigationItems.misc.visible}"] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | | | | | +- recipe-misc-shared-java-script[] - | | | | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | | | | | +- recipe-misc-shared-java-script[@NodeName = "recipe-misc-shared-java-script"] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | | | | | +- recipe-misc-rest-api-call[] - | | | | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | | | | | +- recipe-misc-rest-api-call[@NodeName = "recipe-misc-rest-api-call"] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | | | | | +- recipe-misc-dom-query[] - | | | | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | | | | | +- recipe-misc-dom-query[@NodeName = "recipe-misc-dom-query"] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | | | | | +- recipe-misc-multiple-templates[] - | | | | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | | | | | +- recipe-misc-multiple-templates[@NodeName = "recipe-misc-multiple-templates"] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | | | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | | | | +- template[@if:true = "{navigationItems.party.visible}"] - | | | | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | | | | +- template[@NodeName = "template", @if:true = "{navigationItems.party.visible}"] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | | | | | +- recipe-libs-d3[] - | | | | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | | | | | +- recipe-libs-d3[@NodeName = "recipe-libs-d3"] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | | | | | +- recipe-libs-chartjs[] - | | | | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | | | | | +- recipe-libs-chartjs[@NodeName = "recipe-libs-chartjs"] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | | | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | | | | +- ui-navfooter[@label-next = "{nextNavigationItem}", @label-previous = "{previousNavigationItem}", @onnextclicked = "{handleNavigateNext}", @onpreviousclicked = "{handleNavigatePrevious}"] - | | | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | | | | +- ui-navfooter[@NodeName = "ui-navfooter", @label-next = "{nextNavigationItem}", @label-previous = "{previousNavigationItem}", @onnextclicked = "{handleNavigateNext}", @onpreviousclicked = "{handleNavigatePrevious}"] + | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - | +- #text[@Image = " ", @NormalizedText = " ", @Text = " + | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] - +- #text[@Image = " ", @NormalizedText = " ", @Text = " + +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " "] diff --git a/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/rule/bestpractices/xml/UnnecessaryTypeAttribute.xml b/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/rule/bestpractices/xml/UnnecessaryTypeAttribute.xml new file mode 100644 index 0000000000..a5664b9803 --- /dev/null +++ b/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/rule/bestpractices/xml/UnnecessaryTypeAttribute.xml @@ -0,0 +1,37 @@ + + + + + Example + 2 + 4,5 + + + + + + + + + + + + ]]> + + + + Link refers not a stylesheet + 0 + + + + + +]]> + + From 83c07a540ba93971ea4f2f934d10ac5f290f15cd Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 22 Apr 2022 12:01:55 +0200 Subject: [PATCH 104/180] [html] New rule UseAltAttributeForImages which uses rule chain --- .../pmd/lang/html/ast/ASTHtmlElement.java | 13 +++++++++ .../UnnecessaryTypeAttributeRule.java | 15 +++-------- .../UseAltAttributeForImagesRule.java | 27 +++++++++++++++++++ .../resources/category/html/bestpractices.xml | 22 +++++++++++++++ .../UseAltAttributeForImagesTest.java | 11 ++++++++ .../xml/UseAltAttributeForImages.xml | 23 ++++++++++++++++ 6 files changed, 99 insertions(+), 12 deletions(-) create mode 100644 pmd-html/src/main/java/net/sourceforge/pmd/lang/html/rule/bestpractices/UseAltAttributeForImagesRule.java create mode 100644 pmd-html/src/test/java/net/sourceforge/pmd/lang/html/rule/bestpractices/UseAltAttributeForImagesTest.java create mode 100644 pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/rule/bestpractices/xml/UseAltAttributeForImages.xml diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlElement.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlElement.java index fe01917db9..5ddca95cae 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlElement.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlElement.java @@ -35,6 +35,19 @@ public class ASTHtmlElement extends AbstractHtmlNode { return attributes; } + public boolean hasAttribute(String name) { + return attributes.stream().anyMatch(attribute -> name.equalsIgnoreCase(attribute.getName())); + } + + public String getAttribute(String rel) { + return attributes.stream() + .filter(attribute -> rel.equalsIgnoreCase(attribute.getName())) + .findFirst() + .map(Attribute::getValue) + .map(String::valueOf) + .orElse(null); + } + @Override public Iterator getXPathAttributesIterator() { Iterator defaultAttributes = super.getXPathAttributesIterator(); diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/rule/bestpractices/UnnecessaryTypeAttributeRule.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/rule/bestpractices/UnnecessaryTypeAttributeRule.java index 49f230e92a..b24cadff59 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/rule/bestpractices/UnnecessaryTypeAttributeRule.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/rule/bestpractices/UnnecessaryTypeAttributeRule.java @@ -5,7 +5,6 @@ package net.sourceforge.pmd.lang.html.rule.bestpractices; import net.sourceforge.pmd.RuleContext; -import net.sourceforge.pmd.lang.ast.xpath.Attribute; import net.sourceforge.pmd.lang.html.ast.ASTHtmlElement; import net.sourceforge.pmd.lang.html.rule.AbstractHtmlRule; @@ -22,26 +21,18 @@ public class UnnecessaryTypeAttributeRule extends AbstractHtmlRule { } private void checkScript(ASTHtmlElement node, Object data) { - if (getAttribute(node, "type") != null) { + if (node.hasAttribute("type")) { addViolation(node, data); } } private void checkLink(ASTHtmlElement node, Object data) { - String rel = getAttribute(node, "rel"); - if (getAttribute(node, "type") != null && "stylesheet".equalsIgnoreCase(rel)) { + String rel = node.getAttribute("rel"); + if (node.hasAttribute("type") && "stylesheet".equalsIgnoreCase(rel)) { addViolation(node, data); } } - private String getAttribute(ASTHtmlElement node, String rel) { - return node.getAttributes().stream() - .filter(attribute -> rel.equalsIgnoreCase(attribute.getName())) - .findFirst() - .map(Attribute::getValue) - .map(String::valueOf) - .orElse(null); - } private void addViolation(ASTHtmlElement node, Object data) { RuleContext ctx = (RuleContext) data; diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/rule/bestpractices/UseAltAttributeForImagesRule.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/rule/bestpractices/UseAltAttributeForImagesRule.java new file mode 100644 index 0000000000..cd3895d595 --- /dev/null +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/rule/bestpractices/UseAltAttributeForImagesRule.java @@ -0,0 +1,27 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.html.rule.bestpractices; + +import net.sourceforge.pmd.RuleContext; +import net.sourceforge.pmd.lang.html.ast.ASTHtmlElement; +import net.sourceforge.pmd.lang.html.rule.AbstractHtmlRule; + +public class UseAltAttributeForImagesRule extends AbstractHtmlRule { + + public UseAltAttributeForImagesRule() { + addRuleChainVisit("img"); + } + + @Override + public Object visit(ASTHtmlElement node, Object data) { + if (!node.hasAttribute("alt")) { + RuleContext ctx = (RuleContext) data; + ctx.addViolation(node); + return data; + } + + return data; + } +} diff --git a/pmd-html/src/main/resources/category/html/bestpractices.xml b/pmd-html/src/main/resources/category/html/bestpractices.xml index 565fe30da2..19c07662e9 100644 --- a/pmd-html/src/main/resources/category/html/bestpractices.xml +++ b/pmd-html/src/main/resources/category/html/bestpractices.xml @@ -57,6 +57,28 @@ This helps to reuse common styles. +]]> + + + + + + Always use an "alt" attribute for images. This provides an alternative text and is extensively used + by screen readers. + + 3 + + + + + +A house from the 18th century ]]> diff --git a/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/rule/bestpractices/UseAltAttributeForImagesTest.java b/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/rule/bestpractices/UseAltAttributeForImagesTest.java new file mode 100644 index 0000000000..9bca187b2e --- /dev/null +++ b/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/rule/bestpractices/UseAltAttributeForImagesTest.java @@ -0,0 +1,11 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.html.rule.bestpractices; + +import net.sourceforge.pmd.testframework.PmdRuleTst; + +public class UseAltAttributeForImagesTest extends PmdRuleTst { + // no additional unit tests +} diff --git a/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/rule/bestpractices/xml/UseAltAttributeForImages.xml b/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/rule/bestpractices/xml/UseAltAttributeForImages.xml new file mode 100644 index 0000000000..2090405e20 --- /dev/null +++ b/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/rule/bestpractices/xml/UseAltAttributeForImages.xml @@ -0,0 +1,23 @@ + + + + + Example + 1 + 4 + + + + + + + A house from the 18th century + + + ]]> + + From 0e6ad2dc635c1fc0549c101ce8c5f9c4f43e2c30 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 22 Apr 2022 12:20:02 +0200 Subject: [PATCH 105/180] [html] Add documentation (#3885) --- docs/_data/sidebars/pmd_sidebar.yml | 3 ++ docs/pages/pmd/languages/html.md | 18 +++++++++++ docs/pages/release_notes.md | 30 +++++++++++++++++++ .../main/resources/rulesets/releases/6450.xml | 15 ++++++++++ 4 files changed, 66 insertions(+) create mode 100644 docs/pages/pmd/languages/html.md create mode 100644 pmd-core/src/main/resources/rulesets/releases/6450.xml diff --git a/docs/_data/sidebars/pmd_sidebar.yml b/docs/_data/sidebars/pmd_sidebar.yml index a8a420916f..81d095e398 100644 --- a/docs/_data/sidebars/pmd_sidebar.yml +++ b/docs/_data/sidebars/pmd_sidebar.yml @@ -379,6 +379,9 @@ entries: - title: XML and XML dialects url: /pmd_languages_xml.html output: web, pdf + - title: HTML + url: /pmd_languages_html.html + output: web, pdf - title: Developer Documentation output: web, pdf folderitems: diff --git a/docs/pages/pmd/languages/html.md b/docs/pages/pmd/languages/html.md new file mode 100644 index 0000000000..acb96fc416 --- /dev/null +++ b/docs/pages/pmd/languages/html.md @@ -0,0 +1,18 @@ +--- +title: Processing HTML files +permalink: pmd_languages_html.html +last_updated: April 2022 (6.45.0) +--- + +## The HTML language module + +**Since:** 6.45.0 + +**Minimum Java Runtime:** Java 8 + +{% include warning.html content="This language module is experimental and may change any time." %} + +The HTML language module uses [jsoup](https://jsoup.org/) for parsing. + +XPath rules are supported, but the DOM is not a typical XML/XPath DOM. E.g. +text nodes are normal nodes. This might change in the future. diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 962f226a13..e637b652d1 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -14,6 +14,36 @@ This is a {{ site.pmd.release_type }} release. ### New and noteworthy +#### Support for HTML + +This version of PMD ships a new language module to support analyzing of HTML. +Support for HTML is experimental and might change without notice. + +#### New rules + +* The HTML rule {% rule html/bestpractices/AvoidInlineStyles %} finds elements which use a style attribute. + In order to help maintaining a webpage it is considered good practice to separate content and styles. Instead + of inline styles one should use CSS files and classes. + +```xml + +``` + +* The HTML rule {% rule html/bestpractices/UnnecessaryTypeAttribute %} finds "link" and "script" elements which + still have a "type" attribute. This is not necessary anymore since modern browsers automatically use CSS and + JavaScript. + +```xml + +``` + +* The HTML rule {% rule html/bestpractices/UseAltAttributeForImages %} finds "img" elements without an "alt" + attribute. An alternate text should always be provided in order to help screen readers. + +```xml + +``` + #### Modified rules * The Java rule {% rule java/bestpractices/UnusedPrivateField %} has a new property `ignoredFieldNames`. diff --git a/pmd-core/src/main/resources/rulesets/releases/6450.xml b/pmd-core/src/main/resources/rulesets/releases/6450.xml new file mode 100644 index 0000000000..25ab462ed4 --- /dev/null +++ b/pmd-core/src/main/resources/rulesets/releases/6450.xml @@ -0,0 +1,15 @@ + + + + +This ruleset contains links to rules that are new in PMD v6.45.0 + + + + + + + From c9a1b3fb78f97d82b8bb5158838e8f782d6e10d6 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 22 Apr 2022 16:01:51 +0200 Subject: [PATCH 106/180] [html] Migrate to PMD 7 --- pmd-html/pom.xml | 2 +- .../pmd/lang/html/HtmlHandler.java | 36 +---- .../pmd/lang/html/ast/ASTHtmlCDataNode.java | 2 +- .../pmd/lang/html/ast/ASTHtmlComment.java | 2 +- .../pmd/lang/html/ast/ASTHtmlDocument.java | 18 ++- .../lang/html/ast/ASTHtmlDocumentType.java | 2 +- .../pmd/lang/html/ast/ASTHtmlElement.java | 5 +- .../pmd/lang/html/ast/ASTHtmlTextNode.java | 2 +- .../lang/html/ast/ASTHtmlXmlDeclaration.java | 2 +- .../pmd/lang/html/ast/AbstractHtmlNode.java | 35 ++--- .../pmd/lang/html/ast/HtmlNode.java | 9 +- .../pmd/lang/html/ast/HtmlParser.java | 45 +----- .../pmd/lang/html/ast/HtmlTokenizer.java | 25 ++-- .../pmd/lang/html/ast/HtmlTreeBuilder.java | 16 +- .../pmd/lang/html/ast/HtmlVisitor.java | 39 +++-- .../pmd/lang/html/ast/HtmlVisitorAdapter.java | 51 ------- .../pmd/lang/html/ast/LineNumbers.java | 6 +- .../pmd/lang/html/rule/AbstractHtmlRule.java | 70 +-------- .../UseAltAttributeForImagesRule.java | 10 +- .../pmd/lang/html/HtmlJavaRuleTest.java | 36 ++--- .../pmd/lang/html/HtmlXPathRuleTest.java | 41 +++--- .../pmd/lang/html/ast/HtmlParsingHelper.java | 2 +- .../pmd/lang/html/ast/PositionTest.java | 4 +- .../lang/html/ast/testdata/SimpleHtmlFile.txt | 21 +-- .../html/ast/testdata/SimpleHtmlFile2.txt | 30 ++-- .../lang/html/ast/testdata/SimpleXmlFile.txt | 12 +- .../html/ast/testdata/TemplateFragment.txt | 139 ++++++------------ 27 files changed, 242 insertions(+), 420 deletions(-) delete mode 100644 pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlVisitorAdapter.java diff --git a/pmd-html/pom.xml b/pmd-html/pom.xml index 8e35a9cf2b..9a51a81887 100644 --- a/pmd-html/pom.xml +++ b/pmd-html/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0-SNAPSHOT + 7.0.0-SNAPSHOT ../ diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/HtmlHandler.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/HtmlHandler.java index b6c3ad9659..c5dd4e436b 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/HtmlHandler.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/HtmlHandler.java @@ -5,42 +5,14 @@ package net.sourceforge.pmd.lang.html; -import net.sourceforge.pmd.Rule; -import net.sourceforge.pmd.RuleContext; -import net.sourceforge.pmd.RuleViolation; -import net.sourceforge.pmd.lang.AbstractLanguageVersionHandler; -import net.sourceforge.pmd.lang.Parser; -import net.sourceforge.pmd.lang.ParserOptions; -import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.AbstractPmdLanguageVersionHandler; +import net.sourceforge.pmd.lang.ast.Parser; import net.sourceforge.pmd.lang.html.ast.HtmlParser; -import net.sourceforge.pmd.lang.rule.AbstractRuleViolationFactory; -import net.sourceforge.pmd.lang.rule.ParametricRuleViolation; -import net.sourceforge.pmd.lang.rule.RuleViolationFactory; -class HtmlHandler extends AbstractLanguageVersionHandler { +class HtmlHandler extends AbstractPmdLanguageVersionHandler { @Override - public RuleViolationFactory getRuleViolationFactory() { - return new AbstractRuleViolationFactory() { - - @Override - protected RuleViolation createRuleViolation(Rule rule, RuleContext ruleContext, Node node, String message) { - return new ParametricRuleViolation(rule, ruleContext, node, message); - } - - @Override - protected RuleViolation createRuleViolation(Rule rule, RuleContext ruleContext, Node node, String message, - int beginLine, int endLine) { - ParametricRuleViolation ruleViolation = new ParametricRuleViolation<>(rule, ruleContext, node, message); - ruleViolation.setLines(beginLine, endLine); - return ruleViolation; - } - - }; - } - - @Override - public Parser getParser(ParserOptions parserOptions) { + public Parser getParser() { return new HtmlParser(); } diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlCDataNode.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlCDataNode.java index 1074e740e8..833be67698 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlCDataNode.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlCDataNode.java @@ -18,7 +18,7 @@ public final class ASTHtmlCDataNode extends AbstractHtmlNode { } @Override - public Object acceptVisitor(HtmlVisitor visitor, Object data) { + protected R acceptHtmlVisitor(HtmlVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlComment.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlComment.java index b00053fc90..ae78e81606 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlComment.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlComment.java @@ -18,7 +18,7 @@ public final class ASTHtmlComment extends AbstractHtmlNode { } @Override - public Object acceptVisitor(HtmlVisitor visitor, Object data) { + protected R acceptHtmlVisitor(HtmlVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlDocument.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlDocument.java index b429e463c6..16527686b8 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlDocument.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlDocument.java @@ -5,18 +5,32 @@ package net.sourceforge.pmd.lang.html.ast; +import java.util.Map; + import org.jsoup.nodes.Document; +import net.sourceforge.pmd.lang.ast.AstInfo; +import net.sourceforge.pmd.lang.ast.Parser; import net.sourceforge.pmd.lang.ast.RootNode; public class ASTHtmlDocument extends ASTHtmlElement implements RootNode { - ASTHtmlDocument(Document document) { + private final AstInfo astInfo; + + ASTHtmlDocument(Document document, + Parser.ParserTask task, + Map suppressMap) { super(document); + this.astInfo = new AstInfo<>(task, this, suppressMap); } @Override - public Object acceptVisitor(HtmlVisitor visitor, Object data) { + protected R acceptHtmlVisitor(HtmlVisitor visitor, P data) { return visitor.visit(this, data); } + + @Override + public AstInfo getAstInfo() { + return astInfo; + } } diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlDocumentType.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlDocumentType.java index 0345fa1fc1..8279608c67 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlDocumentType.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlDocumentType.java @@ -14,7 +14,7 @@ public final class ASTHtmlDocumentType extends AbstractHtmlNode { } @Override - public Object acceptVisitor(HtmlVisitor visitor, Object data) { + protected R acceptHtmlVisitor(HtmlVisitor visitor, P data) { return visitor.visit(this, data); } diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlElement.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlElement.java index 5ddca95cae..9efd840ff1 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlElement.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlElement.java @@ -11,7 +11,8 @@ import java.util.List; import org.jsoup.nodes.Element; -import net.sourceforge.pmd.lang.ast.xpath.Attribute; +import net.sourceforge.pmd.lang.rule.xpath.Attribute; + public class ASTHtmlElement extends AbstractHtmlNode { @@ -27,7 +28,7 @@ public class ASTHtmlElement extends AbstractHtmlNode { } @Override - public Object acceptVisitor(HtmlVisitor visitor, Object data) { + protected R acceptHtmlVisitor(HtmlVisitor visitor, P data) { return visitor.visit(this, data); } diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlTextNode.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlTextNode.java index 1f7d7ef07d..524a8a931e 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlTextNode.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlTextNode.java @@ -14,7 +14,7 @@ public class ASTHtmlTextNode extends AbstractHtmlNode { } @Override - public Object acceptVisitor(HtmlVisitor visitor, Object data) { + protected R acceptHtmlVisitor(HtmlVisitor visitor, P data) { return visitor.visit(this, data); } diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlXmlDeclaration.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlXmlDeclaration.java index 87a1ef17ea..da1f98d88d 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlXmlDeclaration.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlXmlDeclaration.java @@ -14,7 +14,7 @@ public final class ASTHtmlXmlDeclaration extends AbstractHtmlNode R acceptHtmlVisitor(HtmlVisitor visitor, P data) { return visitor.visit(this, data); } diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/AbstractHtmlNode.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/AbstractHtmlNode.java index 6517233002..288c80c2cd 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/AbstractHtmlNode.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/AbstractHtmlNode.java @@ -7,14 +7,14 @@ package net.sourceforge.pmd.lang.html.ast; import org.jsoup.nodes.Node; -import net.sourceforge.pmd.lang.ast.AbstractNode; +import net.sourceforge.pmd.lang.ast.AstVisitor; +import net.sourceforge.pmd.lang.ast.impl.AbstractNodeWithTextCoordinates; -abstract class AbstractHtmlNode extends AbstractNode implements HtmlNode { +abstract class AbstractHtmlNode extends AbstractNodeWithTextCoordinates, HtmlNode> implements HtmlNode { protected final T node; AbstractHtmlNode(T node) { - super(0); this.node = node; } @@ -28,23 +28,24 @@ abstract class AbstractHtmlNode extends AbstractNode implements } @Override - public Iterable children() { - return (Iterable) super.children(); + @SuppressWarnings("unchecked") + public final R acceptVisitor(AstVisitor visitor, P data) { + if (visitor instanceof HtmlVisitor) { + return this.acceptHtmlVisitor((HtmlVisitor) visitor, data); + } + return visitor.cannotVisit(this, data); } - void setBeginLine(int beginLine) { - this.beginLine = beginLine; + protected abstract R acceptHtmlVisitor(HtmlVisitor visitor, P data); + + // overridden to make them visible + @Override + protected void addChild(AbstractHtmlNode child, int index) { + super.addChild(child, index); } - void setBeginColumn(int beginColumn) { - this.beginColumn = beginColumn; - } - - void setEndLine(int endLine) { - this.endLine = endLine; - } - - void setEndColumn(int endColumn) { - this.endColumn = endColumn; + @Override + protected void setCoords(int bline, int bcol, int eline, int ecol) { + super.setCoords(bline, bcol, eline, ecol); } } diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlNode.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlNode.java index 820229c82b..4bf784a0f8 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlNode.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlNode.java @@ -5,12 +5,7 @@ package net.sourceforge.pmd.lang.html.ast; -import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.ast.impl.GenericNode; -public interface HtmlNode extends Node { - - @Override - Iterable children(); - - Object acceptVisitor(HtmlVisitor visitor, Object data); +public interface HtmlNode extends GenericNode { } diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlParser.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlParser.java index c61cb4f5a4..a2ce2533b0 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlParser.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlParser.java @@ -5,51 +5,18 @@ package net.sourceforge.pmd.lang.html.ast; -import java.io.IOException; -import java.io.Reader; import java.util.HashMap; -import java.util.Map; -import org.apache.commons.io.IOUtils; import org.jsoup.nodes.Document; import org.jsoup.parser.Parser; -import net.sourceforge.pmd.lang.ParserOptions; -import net.sourceforge.pmd.lang.TokenManager; -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.ast.ParseException; - -public final class HtmlParser implements net.sourceforge.pmd.lang.Parser { +public final class HtmlParser implements net.sourceforge.pmd.lang.ast.Parser { @Override - public boolean canParse() { - return true; - } - - @Override - public Node parse(String fileName, Reader source) throws ParseException { - try { - String data = IOUtils.toString(source); - Document doc = Parser.xmlParser().parseInput(data, ""); - HtmlTreeBuilder builder = new HtmlTreeBuilder(); - return builder.build(doc, data); - } catch (IOException e) { - throw new ParseException(e); - } - } - - @Override - public Map getSuppressMap() { - return new HashMap<>(); // FIXME - } - - @Override - public ParserOptions getParserOptions() { - return new ParserOptions(); - } - - @Override - public TokenManager getTokenManager(String fileName, Reader source) { - return null; + public ASTHtmlDocument parse(ParserTask task) { + String data = task.getSourceText(); + Document doc = Parser.xmlParser().parseInput(data, ""); + HtmlTreeBuilder builder = new HtmlTreeBuilder(); + return builder.build(doc, data, task, new HashMap<>()); } } diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlTokenizer.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlTokenizer.java index a66c53d0ca..f99793cb55 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlTokenizer.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlTokenizer.java @@ -2,27 +2,35 @@ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ - package net.sourceforge.pmd.lang.html.ast; -import org.jsoup.nodes.Document; -import org.jsoup.parser.Parser; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import net.sourceforge.pmd.cpd.SourceCode; import net.sourceforge.pmd.cpd.TokenEntry; import net.sourceforge.pmd.cpd.Tokenizer; import net.sourceforge.pmd.cpd.Tokens; +import net.sourceforge.pmd.lang.LanguageRegistry; +import net.sourceforge.pmd.lang.ast.Parser.ParserTask; +import net.sourceforge.pmd.lang.ast.SemanticErrorReporter; +import net.sourceforge.pmd.lang.html.HtmlLanguageModule; public class HtmlTokenizer implements Tokenizer { + private static final Logger LOG = LoggerFactory.getLogger(HtmlTokenizer.class); @Override public void tokenize(SourceCode sourceCode, Tokens tokenEntries) { - String data = sourceCode.getCodeBuffer().toString(); + ParserTask task = new ParserTask( + LanguageRegistry.getLanguage(HtmlLanguageModule.NAME).getDefaultVersion(), + sourceCode.getFileName(), + sourceCode.getCodeBuffer().toString(), + SemanticErrorReporter.reportToLogger(LOG) + ); + + HtmlParser parser = new HtmlParser(); + ASTHtmlDocument root = parser.parse(task); - Document doc = Parser.xmlParser().parseInput(data, ""); - HtmlTreeBuilder builder = new HtmlTreeBuilder(); - ASTHtmlDocument root = builder.build(doc, data); - traverse(root, tokenEntries); tokenEntries.add(TokenEntry.EOF); } @@ -42,5 +50,4 @@ public class HtmlTokenizer implements Tokenizer { traverse(child, tokenEntries); } } - } diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlTreeBuilder.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlTreeBuilder.java index 4c57243bcf..44d0996fdc 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlTreeBuilder.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlTreeBuilder.java @@ -5,6 +5,8 @@ package net.sourceforge.pmd.lang.html.ast; +import java.util.Map; + import org.jsoup.nodes.CDataNode; import org.jsoup.nodes.Comment; import org.jsoup.nodes.Document; @@ -14,10 +16,12 @@ import org.jsoup.nodes.Node; import org.jsoup.nodes.TextNode; import org.jsoup.nodes.XmlDeclaration; +import net.sourceforge.pmd.lang.ast.Parser; + final class HtmlTreeBuilder { - public ASTHtmlDocument build(Document doc, String htmlString) { - ASTHtmlDocument root = new ASTHtmlDocument(doc); + public ASTHtmlDocument build(Document doc, String htmlString, Parser.ParserTask task, Map suppressMap) { + ASTHtmlDocument root = new ASTHtmlDocument(doc, task, suppressMap); addChildren(root, doc); LineNumbers lineNumbers = new LineNumbers(root, htmlString); @@ -26,15 +30,15 @@ final class HtmlTreeBuilder { return root; } - private void addChildren(HtmlNode parent, Node node) { + private void addChildren(AbstractHtmlNode parent, Node node) { for (Node child : node.childNodes()) { - HtmlNode converted = convertJsoupNode(child); - parent.jjtAddChild(converted, parent.getNumChildren()); + AbstractHtmlNode converted = convertJsoupNode(child); + parent.addChild(converted, parent.getNumChildren()); addChildren(converted, child); } } - private HtmlNode convertJsoupNode(Node node) { + private AbstractHtmlNode convertJsoupNode(Node node) { if (node instanceof Element) { return new ASTHtmlElement((Element) node); } else if (node instanceof CDataNode) { diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlVisitor.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlVisitor.java index 143488ccfc..45f25dc69e 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlVisitor.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlVisitor.java @@ -4,21 +4,42 @@ package net.sourceforge.pmd.lang.html.ast; -public interface HtmlVisitor { +import net.sourceforge.pmd.lang.ast.AstVisitor; - Object visit(HtmlNode node, Object data); +public interface HtmlVisitor extends AstVisitor { - Object visit(ASTHtmlCDataNode node, Object data); + /** + * The default visit method, to which other methods delegate. + */ + default R visitHtmlNode(HtmlNode node, P data) { + return visitNode(node, data); + } - Object visit(ASTHtmlComment node, Object data); + default R visit(ASTHtmlCDataNode node, P data) { + return visitHtmlNode(node, data); + } - Object visit(ASTHtmlDocument node, Object data); + default R visit(ASTHtmlComment node, P data) { + return visitHtmlNode(node, data); + } - Object visit(ASTHtmlDocumentType node, Object data); + default R visit(ASTHtmlDocument node, P data) { + return visitHtmlNode(node, data); + } - Object visit(ASTHtmlElement node, Object data); + default R visit(ASTHtmlDocumentType node, P data) { + return visitHtmlNode(node, data); + } - Object visit(ASTHtmlTextNode node, Object data); + default R visit(ASTHtmlElement node, P data) { + return visitHtmlNode(node, data); + } - Object visit(ASTHtmlXmlDeclaration node, Object data); + default R visit(ASTHtmlTextNode node, P data) { + return visitHtmlNode(node, data); + } + + default R visit(ASTHtmlXmlDeclaration node, P data) { + return visitHtmlNode(node, data); + } } diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlVisitorAdapter.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlVisitorAdapter.java deleted file mode 100644 index 8907439e48..0000000000 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlVisitorAdapter.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.html.ast; - -public class HtmlVisitorAdapter implements HtmlVisitor { - - @Override - public Object visit(HtmlNode node, Object data) { - for (HtmlNode child : node.children()) { - child.acceptVisitor(this, data); - } - return null; - } - - @Override - public Object visit(ASTHtmlCDataNode node, Object data) { - return visit((HtmlNode) node, data); - } - - @Override - public Object visit(ASTHtmlComment node, Object data) { - return visit((HtmlNode) node, data); - } - - @Override - public Object visit(ASTHtmlDocument node, Object data) { - return visit((HtmlNode) node, data); - } - - @Override - public Object visit(ASTHtmlDocumentType node, Object data) { - return visit((HtmlNode) node, data); - } - - @Override - public Object visit(ASTHtmlElement node, Object data) { - return visit((HtmlNode) node, data); - } - - @Override - public Object visit(ASTHtmlTextNode node, Object data) { - return visit((HtmlNode) node, data); - } - - @Override - public Object visit(ASTHtmlXmlDeclaration node, Object data) { - return visit((HtmlNode) node, data); - } -} diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/LineNumbers.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/LineNumbers.java index 11d3517353..6ee33e7c8e 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/LineNumbers.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/LineNumbers.java @@ -82,8 +82,7 @@ class LineNumbers { if (n != null) { int line = sourceCodePositioner.lineNumberFromOffset(index); int column = sourceCodePositioner.columnFromOffset(line, index); - n.setBeginLine(line); - n.setBeginColumn(column); + n.setCoords(line, column, line, column); } } @@ -91,8 +90,7 @@ class LineNumbers { if (n != null) { int line = sourceCodePositioner.lineNumberFromOffset(index); int column = sourceCodePositioner.columnFromOffset(line, index); - n.setEndLine(line); - n.setEndColumn(column); + n.setCoords(n.getBeginLine(), n.getBeginColumn(), line, column); } } } diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/rule/AbstractHtmlRule.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/rule/AbstractHtmlRule.java index c65e21d7e8..246b3dc0eb 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/rule/AbstractHtmlRule.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/rule/AbstractHtmlRule.java @@ -4,20 +4,10 @@ package net.sourceforge.pmd.lang.html.rule; -import java.util.List; - import net.sourceforge.pmd.RuleContext; import net.sourceforge.pmd.lang.LanguageRegistry; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.html.HtmlLanguageModule; -import net.sourceforge.pmd.lang.html.ast.ASTHtmlCDataNode; -import net.sourceforge.pmd.lang.html.ast.ASTHtmlComment; -import net.sourceforge.pmd.lang.html.ast.ASTHtmlDocument; -import net.sourceforge.pmd.lang.html.ast.ASTHtmlDocumentType; -import net.sourceforge.pmd.lang.html.ast.ASTHtmlElement; -import net.sourceforge.pmd.lang.html.ast.ASTHtmlTextNode; -import net.sourceforge.pmd.lang.html.ast.ASTHtmlXmlDeclaration; -import net.sourceforge.pmd.lang.html.ast.HtmlNode; import net.sourceforge.pmd.lang.html.ast.HtmlVisitor; import net.sourceforge.pmd.lang.rule.AbstractRule; @@ -28,63 +18,13 @@ public abstract class AbstractHtmlRule extends AbstractRule implements HtmlVisit } @Override - public void apply(List nodes, RuleContext ctx) { - for (Node node : nodes) { - if (node instanceof HtmlNode) { - ((HtmlNode) node).acceptVisitor(this, ctx); - } - } - } - - // - // The following APIs are identical to those in HtmlVisitorAdapter. - // Due to Java single inheritance, it is preferred to extend from the more - // complex Rule base class instead of from relatively simple Visitor. - // - // CPD-OFF - - @Override - public Object visit(HtmlNode node, Object data) { - for (HtmlNode child : node.children()) { - child.acceptVisitor(this, data); - } - return null; + public Object visitNode(Node node, Object param) { + node.children().forEach(c -> c.acceptVisitor(this, param)); + return param; } @Override - public Object visit(ASTHtmlCDataNode node, Object data) { - return visit((HtmlNode) node, data); + public void apply(Node target, RuleContext ctx) { + target.acceptVisitor(this, ctx); } - - @Override - public Object visit(ASTHtmlComment node, Object data) { - return visit((HtmlNode) node, data); - } - - @Override - public Object visit(ASTHtmlDocument node, Object data) { - return visit((HtmlNode) node, data); - } - - @Override - public Object visit(ASTHtmlDocumentType node, Object data) { - return visit((HtmlNode) node, data); - } - - @Override - public Object visit(ASTHtmlElement node, Object data) { - return visit((HtmlNode) node, data); - } - - @Override - public Object visit(ASTHtmlTextNode node, Object data) { - return visit((HtmlNode) node, data); - } - - @Override - public Object visit(ASTHtmlXmlDeclaration node, Object data) { - return visit((HtmlNode) node, data); - } - - // CPD-ON } diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/rule/bestpractices/UseAltAttributeForImagesRule.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/rule/bestpractices/UseAltAttributeForImagesRule.java index cd3895d595..3cab721591 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/rule/bestpractices/UseAltAttributeForImagesRule.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/rule/bestpractices/UseAltAttributeForImagesRule.java @@ -4,14 +4,20 @@ package net.sourceforge.pmd.lang.html.rule.bestpractices; +import java.util.Arrays; + +import org.checkerframework.checker.nullness.qual.NonNull; + import net.sourceforge.pmd.RuleContext; import net.sourceforge.pmd.lang.html.ast.ASTHtmlElement; import net.sourceforge.pmd.lang.html.rule.AbstractHtmlRule; +import net.sourceforge.pmd.lang.rule.RuleTargetSelector; public class UseAltAttributeForImagesRule extends AbstractHtmlRule { - public UseAltAttributeForImagesRule() { - addRuleChainVisit("img"); + @Override + protected @NonNull RuleTargetSelector buildTargetSelector() { + return RuleTargetSelector.forXPathNames(Arrays.asList("img")); } @Override diff --git a/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/HtmlJavaRuleTest.java b/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/HtmlJavaRuleTest.java index 307a7aef74..6f0acc19b9 100644 --- a/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/HtmlJavaRuleTest.java +++ b/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/HtmlJavaRuleTest.java @@ -4,22 +4,24 @@ package net.sourceforge.pmd.lang.html; -import java.io.StringReader; -import java.util.Arrays; +import java.util.ArrayList; +import java.util.List; import org.junit.Assert; import org.junit.Test; -import net.sourceforge.pmd.Report; import net.sourceforge.pmd.Rule; import net.sourceforge.pmd.RuleContext; +import net.sourceforge.pmd.RuleViolation; import net.sourceforge.pmd.lang.LanguageRegistry; import net.sourceforge.pmd.lang.LanguageVersion; -import net.sourceforge.pmd.lang.Parser; import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.ast.xpath.Attribute; +import net.sourceforge.pmd.lang.ast.Parser; +import net.sourceforge.pmd.lang.ast.Parser.ParserTask; +import net.sourceforge.pmd.lang.ast.SemanticErrorReporter; import net.sourceforge.pmd.lang.html.ast.ASTHtmlElement; import net.sourceforge.pmd.lang.html.rule.AbstractHtmlRule; +import net.sourceforge.pmd.lang.rule.xpath.Attribute; public class HtmlJavaRuleTest { // from https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.js_props_getter @@ -54,21 +56,21 @@ public class HtmlJavaRuleTest { return super.visit(node, data); } }; - Report report = runRule(LIGHTNING_WEB_COMPONENT, rule); - Assert.assertEquals(2, report.getViolations().size()); - Assert.assertEquals(4, report.getViolations().get(0).getBeginLine()); - Assert.assertEquals(6, report.getViolations().get(1).getBeginLine()); + List violations = runRule(LIGHTNING_WEB_COMPONENT, rule); + Assert.assertEquals(2, violations.size()); + Assert.assertEquals(4, violations.get(0).getBeginLine()); + Assert.assertEquals(6, violations.get(1).getBeginLine()); } - private Report runRule(String html, Rule rule) { + private List runRule(String html, Rule rule) { LanguageVersion htmlLanguage = LanguageRegistry.findLanguageByTerseName(HtmlLanguageModule.TERSE_NAME).getDefaultVersion(); - Parser parser = htmlLanguage.getLanguageVersionHandler().getParser(htmlLanguage.getLanguageVersionHandler().getDefaultParserOptions()); + Parser parser = htmlLanguage.getLanguageVersionHandler().getParser(); + ParserTask parserTask = new ParserTask(htmlLanguage, "n/a", html, SemanticErrorReporter.noop()); + Node node = parser.parse(parserTask); - Node node = parser.parse("n/a", new StringReader(html)); - RuleContext context = new RuleContext(); - context.setLanguageVersion(htmlLanguage); - context.setCurrentRule(rule); - rule.apply(Arrays.asList(node), context); - return context.getReport(); + List violations = new ArrayList<>(); + RuleContext context = RuleContext.create(violations::add, rule); + rule.apply(node, context); + return violations; } } diff --git a/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/HtmlXPathRuleTest.java b/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/HtmlXPathRuleTest.java index 6c2c53e2f9..f6dca7ab97 100644 --- a/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/HtmlXPathRuleTest.java +++ b/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/HtmlXPathRuleTest.java @@ -4,18 +4,20 @@ package net.sourceforge.pmd.lang.html; -import java.io.StringReader; -import java.util.Arrays; +import java.util.ArrayList; +import java.util.List; import org.junit.Assert; import org.junit.Test; -import net.sourceforge.pmd.Report; import net.sourceforge.pmd.RuleContext; +import net.sourceforge.pmd.RuleViolation; import net.sourceforge.pmd.lang.LanguageRegistry; import net.sourceforge.pmd.lang.LanguageVersion; -import net.sourceforge.pmd.lang.Parser; import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.ast.Parser; +import net.sourceforge.pmd.lang.ast.Parser.ParserTask; +import net.sourceforge.pmd.lang.ast.SemanticErrorReporter; import net.sourceforge.pmd.lang.rule.XPathRule; import net.sourceforge.pmd.lang.rule.xpath.XPathVersion; @@ -38,9 +40,9 @@ public class HtmlXPathRuleTest { // "Don’t add spaces around the property, for example, { data } is not valid HTML." String xpath = "//*[local-name() = '#text'][contains(@Text, '{ ')]"; - Report report = runXPath(LIGHTNING_WEB_COMPONENT, xpath); - Assert.assertEquals(1, report.getViolations().size()); - Assert.assertEquals(3, report.getViolations().get(0).getBeginLine()); + List violations = runXPath(LIGHTNING_WEB_COMPONENT, xpath); + Assert.assertEquals(1, violations.size()); + Assert.assertEquals(3, violations.get(0).getBeginLine()); } @Test @@ -49,22 +51,23 @@ public class HtmlXPathRuleTest { // "Don’t add spaces around the property, for example, { data } is not valid HTML." String xpath = "//*[@value = '{']"; - Report report = runXPath(LIGHTNING_WEB_COMPONENT, xpath); - Assert.assertEquals(1, report.getViolations().size()); - Assert.assertEquals(4, report.getViolations().get(0).getBeginLine()); + List violations = runXPath(LIGHTNING_WEB_COMPONENT, xpath); + Assert.assertEquals(1, violations.size()); + Assert.assertEquals(4, violations.get(0).getBeginLine()); } - private Report runXPath(String html, String xpath) { + private List runXPath(String html, String xpath) { LanguageVersion htmlLanguage = LanguageRegistry.findLanguageByTerseName(HtmlLanguageModule.TERSE_NAME).getDefaultVersion(); - Parser parser = htmlLanguage.getLanguageVersionHandler().getParser(htmlLanguage.getLanguageVersionHandler().getDefaultParserOptions()); + Parser parser = htmlLanguage.getLanguageVersionHandler().getParser(); + ParserTask parserTask = new ParserTask(htmlLanguage, "n/a", html, SemanticErrorReporter.noop()); + Node node = parser.parse(parserTask); - XPathRule rule = new XPathRule(XPathVersion.XPATH_2_0, xpath); + List violations = new ArrayList<>(); + XPathRule rule = new XPathRule(XPathVersion.DEFAULT, xpath); rule.setMessage("test"); - Node node = parser.parse("n/a", new StringReader(html)); - RuleContext context = new RuleContext(); - context.setLanguageVersion(htmlLanguage); - context.setCurrentRule(rule); - rule.apply(Arrays.asList(node), context); - return context.getReport(); + rule.setLanguage(htmlLanguage.getLanguage()); + RuleContext context = RuleContext.create(violations::add, rule); + rule.apply(node, context); + return violations; } } diff --git a/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/ast/HtmlParsingHelper.java b/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/ast/HtmlParsingHelper.java index 37812e7f1c..ded77d2816 100644 --- a/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/ast/HtmlParsingHelper.java +++ b/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/ast/HtmlParsingHelper.java @@ -9,7 +9,7 @@ import net.sourceforge.pmd.lang.html.HtmlLanguageModule; public final class HtmlParsingHelper extends BaseParsingHelper { - public static final HtmlParsingHelper DEFAULT = new HtmlParsingHelper(Params.getDefaultProcess()); + public static final HtmlParsingHelper DEFAULT = new HtmlParsingHelper(Params.getDefault()); private HtmlParsingHelper(Params params) { super(HtmlLanguageModule.NAME, ASTHtmlDocument.class, params); diff --git a/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/ast/PositionTest.java b/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/ast/PositionTest.java index 37b7d21322..342bbc957f 100644 --- a/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/ast/PositionTest.java +++ b/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/ast/PositionTest.java @@ -13,7 +13,7 @@ import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.ast.test.BaseNodeAttributePrinter; import net.sourceforge.pmd.lang.ast.test.BaseParsingHelper; import net.sourceforge.pmd.lang.ast.test.BaseTreeDumpTest; -import net.sourceforge.pmd.lang.ast.xpath.Attribute; +import net.sourceforge.pmd.lang.rule.xpath.Attribute; import net.sourceforge.pmd.util.CollectionUtil; public class PositionTest extends BaseTreeDumpTest { @@ -32,7 +32,7 @@ public class PositionTest extends BaseTreeDumpTest { } private static class PositionRenderer extends BaseNodeAttributePrinter { - private final Set pos = CollectionUtil.asSet(new String[] {"BeginLine", "BeginColumn", "EndLine", "EndColumn"}); + private final Set pos = CollectionUtil.setOf("BeginLine", "BeginColumn", "EndLine", "EndColumn"); @Override protected boolean ignoreAttribute(Node node, Attribute attribute) { diff --git a/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/ast/testdata/SimpleHtmlFile.txt b/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/ast/testdata/SimpleHtmlFile.txt index 058a83898d..6d8af325b6 100644 --- a/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/ast/testdata/SimpleHtmlFile.txt +++ b/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/ast/testdata/SimpleHtmlFile.txt @@ -1,22 +1,15 @@ +- #document[@NodeName = "#document"] +- #doctype[@Name = "html", @NodeName = "#doctype", @PublicId = "", @SystemId = ""] - +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " -"] + +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n"] +- html[@NodeName = "html"] - | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | +- head[@NodeName = "head"] | | +- #text[@Image = "hello", @NodeName = "#text", @NormalizedText = "hello", @Text = "hello"] - | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | +- body[@NodeName = "body"] - | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | +- h1[@NodeName = "h1"] | | | +- #text[@Image = "world", @NodeName = "#text", @NormalizedText = "world", @Text = "world"] - | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] - | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " -"] - +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " -"] + | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] + | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n"] + +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n"] diff --git a/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/ast/testdata/SimpleHtmlFile2.txt b/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/ast/testdata/SimpleHtmlFile2.txt index 6e90423dff..8bc595502f 100644 --- a/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/ast/testdata/SimpleHtmlFile2.txt +++ b/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/ast/testdata/SimpleHtmlFile2.txt @@ -1,15 +1,15 @@ -+- #document[@BeginColumn = 1, @BeginLine = 1, @EndColumn = 8, @EndLine = 7] - +- #doctype[@BeginColumn = 1, @BeginLine = 1, @EndColumn = 15, @EndLine = 1] - +- #text[@BeginColumn = 16, @BeginLine = 1, @EndColumn = 16, @EndLine = 1] - +- html[@BeginColumn = 1, @BeginLine = 2, @EndColumn = 7, @EndLine = 7] - | +- #text[@BeginColumn = 7, @BeginLine = 2, @EndColumn = 4, @EndLine = 3] - | +- head[@BeginColumn = 5, @BeginLine = 3, @EndColumn = 22, @EndLine = 3] - | | +- #text[@BeginColumn = 11, @BeginLine = 3, @EndColumn = 15, @EndLine = 3] - | +- #text[@BeginColumn = 23, @BeginLine = 3, @EndColumn = 4, @EndLine = 4] - | +- body[@BeginColumn = 5, @BeginLine = 4, @EndColumn = 11, @EndLine = 6] - | | +- #text[@BeginColumn = 11, @BeginLine = 4, @EndColumn = 8, @EndLine = 5] - | | +- h1[@BeginColumn = 9, @BeginLine = 5, @EndColumn = 22, @EndLine = 5] - | | | +- #text[@BeginColumn = 13, @BeginLine = 5, @EndColumn = 17, @EndLine = 5] - | | +- #text[@BeginColumn = 23, @BeginLine = 5, @EndColumn = 4, @EndLine = 6] - | +- #text[@BeginColumn = 12, @BeginLine = 6, @EndColumn = 12, @EndLine = 6] - +- #text[@BeginColumn = 8, @BeginLine = 7, @EndColumn = 8, @EndLine = 7] ++- #document[@BeginColumn = "1", @BeginLine = "1", @EndColumn = "8", @EndLine = "7"] + +- #doctype[@BeginColumn = "1", @BeginLine = "1", @EndColumn = "15", @EndLine = "1"] + +- #text[@BeginColumn = "16", @BeginLine = "1", @EndColumn = "16", @EndLine = "1"] + +- html[@BeginColumn = "1", @BeginLine = "2", @EndColumn = "7", @EndLine = "7"] + | +- #text[@BeginColumn = "7", @BeginLine = "2", @EndColumn = "4", @EndLine = "3"] + | +- head[@BeginColumn = "5", @BeginLine = "3", @EndColumn = "22", @EndLine = "3"] + | | +- #text[@BeginColumn = "11", @BeginLine = "3", @EndColumn = "15", @EndLine = "3"] + | +- #text[@BeginColumn = "23", @BeginLine = "3", @EndColumn = "4", @EndLine = "4"] + | +- body[@BeginColumn = "5", @BeginLine = "4", @EndColumn = "11", @EndLine = "6"] + | | +- #text[@BeginColumn = "11", @BeginLine = "4", @EndColumn = "8", @EndLine = "5"] + | | +- h1[@BeginColumn = "9", @BeginLine = "5", @EndColumn = "22", @EndLine = "5"] + | | | +- #text[@BeginColumn = "13", @BeginLine = "5", @EndColumn = "17", @EndLine = "5"] + | | +- #text[@BeginColumn = "23", @BeginLine = "5", @EndColumn = "4", @EndLine = "6"] + | +- #text[@BeginColumn = "12", @BeginLine = "6", @EndColumn = "12", @EndLine = "6"] + +- #text[@BeginColumn = "8", @BeginLine = "7", @EndColumn = "8", @EndLine = "7"] diff --git a/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/ast/testdata/SimpleXmlFile.txt b/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/ast/testdata/SimpleXmlFile.txt index a5c715bfb0..9c25c1a1fc 100644 --- a/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/ast/testdata/SimpleXmlFile.txt +++ b/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/ast/testdata/SimpleXmlFile.txt @@ -1,13 +1,9 @@ +- #document[@NodeName = "#document"] +- #declaration[@Name = "xml", @NodeName = "#declaration"] - +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " -"] + +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n"] +- root[@NodeName = "root"] - | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | +- child[@NodeName = "child", @attr1 = "value1"] | | +- #text[@Image = "text & entities", @NodeName = "#text", @NormalizedText = "text & entities", @Text = "text & entities"] - | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " -"] - +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " -"] + | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n"] + +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n"] diff --git a/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/ast/testdata/TemplateFragment.txt b/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/ast/testdata/TemplateFragment.txt index c9e048e3be..6b4d6a4f40 100644 --- a/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/ast/testdata/TemplateFragment.txt +++ b/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/ast/testdata/TemplateFragment.txt @@ -1,130 +1,83 @@ +- #document[@NodeName = "#document"] +- #comment[@Data = " from https://raw.githubusercontent.com/trailheadapps/lwc-recipes-oss/main/src/modules/ui/app/app.html ", @NodeName = "#comment"] - +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " -"] + +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n"] +- template[@NodeName = "template"] - | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | +- section[@NodeName = "section", @class = "content container page-background"] - | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | +- ui-navbar[@NodeName = "ui-navbar", @nav-items = "{navigationItems}", @oncategorychange = "{handleCategoryChange}", @selected-item = "{currentNavigationItem}"] - | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] - | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - - "] + | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] + | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n\n "] | | +- article[@NodeName = "article", @class = "container"] - | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | +- div[@NodeName = "div"] - | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | +- template[@NodeName = "template", @if:true = "{navigationItems.hello.visible}"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-hello[@NodeName = "recipe-hello"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-hello-binding[@NodeName = "recipe-hello-binding"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-hello-expressions[@NodeName = "recipe-hello-expressions"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-hello-expressions-track[@NodeName = "recipe-hello-expressions-track"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-hello-conditional-rendering[@NodeName = "recipe-hello-conditional-rendering"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-hello-for-each[@NodeName = "recipe-hello-for-each"] | | | | | +- recipe-hello-iterator[@NodeName = "recipe-hello-iterator"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] - | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] + | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | +- template[@NodeName = "template", @if:true = "{navigationItems.composition.visible}"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-composition-basics[@NodeName = "recipe-composition-basics"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-composition-iteration[@NodeName = "recipe-composition-iteration"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-composition-contact-search[@NodeName = "recipe-composition-contact-search"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-composition-dynamic[@NodeName = "recipe-composition-dynamic"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] - | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] + | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | +- template[@NodeName = "template", @if:true = "{navigationItems.child.visible}"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-event-simple[@NodeName = "recipe-event-simple"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-event-with-data[@NodeName = "recipe-event-with-data"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-event-bubbling[@NodeName = "recipe-event-bubbling"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] - | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] + | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | +- template[@NodeName = "template", @if:true = "{navigationItems.parent.visible}"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-api-property[@NodeName = "recipe-api-property"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-api-function[@NodeName = "recipe-api-function"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-api-setter-getter[@NodeName = "recipe-api-setter-getter"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] - | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] + | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | +- template[@NodeName = "template", @if:true = "{navigationItems.misc.visible}"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-misc-shared-java-script[@NodeName = "recipe-misc-shared-java-script"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-misc-rest-api-call[@NodeName = "recipe-misc-rest-api-call"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-misc-dom-query[@NodeName = "recipe-misc-dom-query"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-misc-multiple-templates[@NodeName = "recipe-misc-multiple-templates"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] - | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] + | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | +- template[@NodeName = "template", @if:true = "{navigationItems.party.visible}"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-libs-d3[@NodeName = "recipe-libs-d3"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-libs-chartjs[@NodeName = "recipe-libs-chartjs"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] - | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] + | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | +- ui-navfooter[@NodeName = "ui-navfooter", @label-next = "{nextNavigationItem}", @label-previous = "{previousNavigationItem}", @onnextclicked = "{handleNavigateNext}", @onpreviousclicked = "{handleNavigatePrevious}"] - | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] - | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] - | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] - | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " -"] - +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " -"] + | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] + | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] + | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] + | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n"] + +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n"] From 2a0ce95a992d25ed96a592dbfaaad4febe11c0cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 22 Apr 2022 20:41:25 +0200 Subject: [PATCH 107/180] Change a Chars method --- .../sourceforge/pmd/lang/document/Chars.java | 17 +++++----- .../net/sourceforge/pmd/RuleContextTest.java | 6 +++- .../net/sourceforge/pmd/ant/PMDTaskTest.java | 6 ---- .../sourceforge/pmd/lang/ast/DummyNode.java | 30 +++++++++++------ .../pmd/lang/document/CharsTest.java | 32 ++++++++++++++++++- .../pmd/ant/xml/expected-pmd-ant-xml.xml | 2 +- 6 files changed, 65 insertions(+), 28 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java index d55562b822..664a58330c 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java @@ -346,21 +346,20 @@ public final class Chars implements CharSequence { } /** - * Returns the substring starting at the given offset and with the - * given length. This differs from {@link String#substring(int, int)} - * in that it uses offset + length instead of start + end. + * Returns the substring between the given offsets. + * given length. * - * @param off Start offset ({@code 0 <= off < this.length()}) - * @param len Length of the substring ({@code 0 <= len <= this.length() - off}) + * @param start Start offset ({@code 0 <= start < this.length()}) + * @param end End offset ({@code start <= end <= this.length()}) * * @return A substring * * @throws IndexOutOfBoundsException If the parameters are not a valid range + * @see String#substring(int, int) */ - public String substring(int off, int len) { - validateRange(off, len, this.len); - int start = idx(off); - return str.substring(start, start + len); + public String substring(int start, int end) { + validateRange(start, end - start, this.len); + return str.substring(idx(start), idx(end)); } private static void validateRangeWithAssert(int off, int len, int bound) { diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/RuleContextTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/RuleContextTest.java index 835d227dbb..a24170661a 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/RuleContextTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/RuleContextTest.java @@ -9,6 +9,7 @@ import java.util.function.BiConsumer; import org.junit.Assert; import org.junit.Test; +import net.sourceforge.pmd.lang.ast.DummyNode.DummyRootNode; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.ast.RootNode; import net.sourceforge.pmd.lang.ast.impl.DummyTreeUtil; @@ -49,7 +50,10 @@ public class RuleContextTest { } private RuleViolation makeViolation(String unescapedMessage, Object... args) throws Exception { - Report report = getReport(new FooRule(), (r, ctx) -> ctx.addViolationWithMessage(DummyTreeUtil.tree(DummyTreeUtil::root), unescapedMessage, args)); + Report report = getReport(new FooRule(), (r, ctx) -> { + DummyRootNode node = DummyTreeUtil.tree(DummyTreeUtil::root); + ctx.addViolationWithMessage(node, unescapedMessage, args); + }); return report.getViolations().get(0); } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/ant/PMDTaskTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/ant/PMDTaskTest.java index 6e2ae33f8f..ba7970fca1 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/ant/PMDTaskTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/ant/PMDTaskTest.java @@ -110,12 +110,6 @@ public class PMDTaskTest { expected = expected.replaceFirst("timestamp=\"[^\"]+\"", "timestamp=\"\""); expected = expected.replaceFirst("\\.xsd\" version=\"[^\"]+\"", ".xsd\" version=\"\""); - // under windows, the file source sample.dummy has different line endings - // and therefore the endcolumn of the nodes also change - if (System.lineSeparator().equals("\r\n")) { - expected = expected.replaceFirst("endcolumn=\"109\"", "endcolumn=\"110\""); - } - Assert.assertEquals(expected, actual); } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/DummyNode.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/DummyNode.java index 92d3aa8740..ed94e8ccc2 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/DummyNode.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/DummyNode.java @@ -5,7 +5,6 @@ package net.sourceforge.pmd.lang.ast; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -154,28 +153,39 @@ public class DummyNode extends AbstractNode implements Gen public static class DummyRootNode extends DummyNode implements RootNode { - private Map suppressMap = Collections.emptyMap(); - private TextDocument sourceText = TextDocument.readOnlyString( - "dummy text", - TextFile.UNKNOWN_FILENAME, - DummyLanguageModule.getInstance().getDefaultVersion() - ); - private AstInfo astInfo; + public DummyRootNode() { + TextDocument document = TextDocument.readOnlyString( + "dummy text", + TextFile.UNKNOWN_FILENAME, + DummyLanguageModule.getInstance().getDefaultVersion() + ); + astInfo = new AstInfo<>( + new ParserTask( + document, + SemanticErrorReporter.noop() + ), + this); + } + public DummyRootNode withTaskInfo(ParserTask task) { this.astInfo = new AstInfo<>(task, this); return this; } public DummyRootNode withNoPmdComments(Map suppressMap) { - this.suppressMap = suppressMap; + this.astInfo = new AstInfo<>( + astInfo.getTextDocument(), + this, + suppressMap + ); return this; } @Override public AstInfo getAstInfo() { - return Objects.requireNonNull(astInfo, "no ast info, don't use DummyRootNode's ctor directly"); + return Objects.requireNonNull(astInfo, "no ast info"); } @Override diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/CharsTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/CharsTest.java index 762bf68b2a..e872f0e288 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/CharsTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/CharsTest.java @@ -77,7 +77,7 @@ public class CharsTest { Chars bc = Chars.wrap("abcd").slice(1, 2); bc.getChars(0, arr, 1, 2); - assertArrayEquals(arr, new char[] {0, 'b', 'c', 0}); + assertArrayEquals(arr, new char[] { 0, 'b', 'c', 0 }); assertThrows(IndexOutOfBoundsException.class, () -> bc.getChars(2, arr, 0, 1)); assertThrows(IndexOutOfBoundsException.class, () -> bc.getChars(-1, arr, 0, 1)); @@ -232,4 +232,34 @@ public class CharsTest { assertTrue(chars.contentEquals(Chars.wrap("A_B_C"), true)); } + @Test + public void testSlice() { + // slice is offset + length + Chars chars = Chars.wrap("a_a_b_c_s").slice(2, 5); + // ----- + assertEquals(Chars.wrap("_b_"), chars.slice(1, 3)); + assertThrows(IndexOutOfBoundsException.class, () -> chars.slice(0, -1)); + assertThrows(IndexOutOfBoundsException.class, () -> chars.slice(0, 6)); + } + + @Test + public void testSubsequence() { + // subsequence is start + end + Chars chars = Chars.wrap("a_a_b_c_s").slice(2, 5); + // ----- + assertEquals(Chars.wrap("_b"), chars.subSequence(1, 3)); + assertThrows(IndexOutOfBoundsException.class, () -> chars.slice(0, -1)); + assertThrows(IndexOutOfBoundsException.class, () -> chars.slice(0, 6)); + } + + @Test + public void testSubstring() { + // substring is start + end + Chars chars = Chars.wrap("a_a_b_c_s").slice(2, 5); + // ----- + assertEquals("_b", chars.substring(1, 3)); + assertThrows(IndexOutOfBoundsException.class, () -> chars.substring(0, -1)); + assertThrows(IndexOutOfBoundsException.class, () -> chars.substring(0, 6)); + } + } diff --git a/pmd-core/src/test/resources/net/sourceforge/pmd/ant/xml/expected-pmd-ant-xml.xml b/pmd-core/src/test/resources/net/sourceforge/pmd/ant/xml/expected-pmd-ant-xml.xml index 0bfe352391..081d871709 100644 --- a/pmd-core/src/test/resources/net/sourceforge/pmd/ant/xml/expected-pmd-ant-xml.xml +++ b/pmd-core/src/test/resources/net/sourceforge/pmd/ant/xml/expected-pmd-ant-xml.xml @@ -1,7 +1,7 @@ - + Test Rule 2 From 1a2682d5f84a820d9551276c47748fd356b4f1e7 Mon Sep 17 00:00:00 2001 From: wsf <1912125562@qq.com> Date: Sat, 23 Apr 2022 17:31:16 +0800 Subject: [PATCH 108/180] fix ExecuteImmediateBulkCollect bug and add some test cases --- pmd-plsql/etc/grammar/PldocAST.jjt | 1 + .../ast/ExecuteImmediateBulkCollectTest.java | 30 +++++++++++++++++++ .../ast/ExecuteImmediateBulkCollect1.pls | 15 ++++++++++ .../ast/ExecuteImmediateBulkCollect2.pls | 26 ++++++++++++++++ .../ast/ExecuteImmediateBulkCollect3.pls | 21 +++++++++++++ 5 files changed, 93 insertions(+) create mode 100644 pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollectTest.java create mode 100644 pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect1.pls create mode 100644 pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect2.pls create mode 100644 pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect3.pls diff --git a/pmd-plsql/etc/grammar/PldocAST.jjt b/pmd-plsql/etc/grammar/PldocAST.jjt index 0641868f00..1ec8e28725 100644 --- a/pmd-plsql/etc/grammar/PldocAST.jjt +++ b/pmd-plsql/etc/grammar/PldocAST.jjt @@ -2818,6 +2818,7 @@ ASTEmbeddedSqlStatement EmbeddedSqlStatement() : {} { StringExpression() + [ LOOKAHEAD() BulkCollectIntoClause() ] //#3687 Invoke this method to parse BULK COLLECT [ Name() ("," Name())* ] [ UsingClause() ] [ ( | ) Expression() ("," Expression())*] ";" diff --git a/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollectTest.java b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollectTest.java new file mode 100644 index 0000000000..8def0bb7af --- /dev/null +++ b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollectTest.java @@ -0,0 +1,30 @@ +/** + * 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 ExecuteImmediateBulkCollectTest extends AbstractPLSQLParserTst { + @Test + public void testExecuteImmediateBulkCollect1() { + ASTInput input = plsql.parseResource("ExecuteImmediateBulkCollect1.pls"); + Assert.assertNotNull(input); + } + + @Test + public void testExecuteImmediateBulkCollect2() { + ASTInput input = plsql.parseResource("ExecuteImmediateBulkCollect2.pls"); + Assert.assertNotNull(input); + } + + @Test + public void testExecuteImmediateBulkCollect3() { + ASTInput input = plsql.parseResource("ExecuteImmediateBulkCollect3.pls"); + Assert.assertNotNull(input); + } +} diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect1.pls b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect1.pls new file mode 100644 index 0000000000..f4951287e3 --- /dev/null +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect1.pls @@ -0,0 +1,15 @@ +CREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS + -- + TYPE t_data IS TABLE OF dual%ROWTYPE INDEX BY BINARY_INTEGER; + -- + l_data t_data; + l_sql VARCHAR2(500); + -- +BEGIN + -- + l_sql := 'SELECT * FROM DUAL'; + -- + EXECUTE IMMEDIATE l_sql BULK COLLECT + INTO l_data; + -- +END EXAMPLE_PROCEDURE; \ No newline at end of file diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect2.pls b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect2.pls new file mode 100644 index 0000000000..bde3fe091e --- /dev/null +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect2.pls @@ -0,0 +1,26 @@ +CREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS + -- + TYPE t_data_key IS TABLE OF NUMBER INDEX BY BINARY_INTEGER; + TYPE t_data_description IS TABLE OF VARCHAR2(100) INDEX BY BINARY_INTEGER; + -- + l_data_key t_data_key; + l_data_description t_data_description; + l_sql VARCHAR2(500); + p_rownum1 NUMBER(20); + p_rownum2 NUMBER(20); + -- +BEGIN + -- + p_rownum1 := 10; + p_rownum2 := 30; + -- + l_sql := 'SELECT 1, ' || CHR(39) || 'First key' || CHR(39) || + ' FROM DUAL '||' WHERE ROWNUM <= :p_rownum1 ' || + 'UNION ALL '|| + 'SELECT 2, ' || CHR(39) || 'Second key ' || CHR(39) || + ' FROM DUAL'||' WHERE ROWNUM <= :p_rownum2 '; + -- + EXECUTE IMMEDIATE l_sql BULK COLLECT + INTO l_data_key, l_data_description USING p_rownum1, p_rownum2; + -- +END EXAMPLE_PROCEDURE; \ No newline at end of file diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect3.pls b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect3.pls new file mode 100644 index 0000000000..74270792e3 --- /dev/null +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect3.pls @@ -0,0 +1,21 @@ +CREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS + -- + TYPE t_data_key IS TABLE OF NUMBER INDEX BY BINARY_INTEGER; + TYPE t_data_description IS TABLE OF VARCHAR2(100) INDEX BY BINARY_INTEGER; + -- + l_data_key t_data_key; + l_data_description t_data_description; + l_sql VARCHAR2(500); + -- +BEGIN + -- + l_sql := 'SELECT 1, ' || CHR(39) || 'First key' || CHR(39) || + ' FROM DUAL '|| + 'UNION ALL '|| + 'SELECT 2, ' || CHR(39) || 'Second key ' || CHR(39) || + ' FROM DUAL'; + -- + EXECUTE IMMEDIATE l_sql BULK COLLECT + INTO l_data_key, l_data_description; + -- +END EXAMPLE_PROCEDURE; \ No newline at end of file From 246436ac7fbc2935807a6778c2a29513119d45ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sat, 23 Apr 2022 15:56:38 +0200 Subject: [PATCH 109/180] Fix tests on windows Bug in toLocation(Range2d) Use RulePriority.LOW as default in PMDTask, so as not to create IndexOutOfBoundsException every time --- pmd-core/src/main/java/net/sourceforge/pmd/ant/PMDTask.java | 3 ++- .../java/net/sourceforge/pmd/lang/document/TextDocument.java | 2 +- .../src/test/java/net/sourceforge/pmd/ant/PMDTaskTest.java | 4 +++- .../net/sourceforge/pmd/ant/xml/expected-pmd-ant-xml.xml | 3 +++ pmd-core/src/test/resources/rulesets/dummy/basic.xml | 2 +- 5 files changed, 10 insertions(+), 4 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/ant/PMDTask.java b/pmd-core/src/main/java/net/sourceforge/pmd/ant/PMDTask.java index ba9367ad15..192a714f6e 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/ant/PMDTask.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/ant/PMDTask.java @@ -15,6 +15,7 @@ import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.Path; import org.apache.tools.ant.types.Reference; +import net.sourceforge.pmd.RulePriority; import net.sourceforge.pmd.ant.internal.PMDTaskImpl; public class PMDTask extends Task { @@ -31,7 +32,7 @@ public class PMDTask extends Task { private boolean noRuleSetCompatibility; private String encoding; private int threads = 1; // same default as in PMDParameters (CLI) - private int minimumPriority; + private int minimumPriority = RulePriority.LOW.getPriority(); // inclusive private int maxRuleViolations = 0; private String failuresPropertyName; private SourceLanguage sourceLanguage; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextDocument.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextDocument.java index f26e4abfc8..6c6f95b48c 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextDocument.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextDocument.java @@ -157,7 +157,7 @@ public interface TextDocument extends Closeable { * @throws IndexOutOfBoundsException If the argument is not a valid region in this document */ default FileLocation toLocation(TextRange2d range) { - int startOffset = offsetAtLineColumn(range.getEndPos()); + int startOffset = offsetAtLineColumn(range.getStartPos()); if (startOffset < 0) { throw new IndexOutOfBoundsException("Region out of bounds: " + range.displayString()); } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/ant/PMDTaskTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/ant/PMDTaskTest.java index ba7970fca1..0e4666817c 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/ant/PMDTaskTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/ant/PMDTaskTest.java @@ -4,6 +4,8 @@ package net.sourceforge.pmd.ant; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; import static org.junit.Assert.fail; import java.io.FileInputStream; @@ -92,7 +94,7 @@ public class PMDTaskTest { String actual = IOUtils.toString(in, StandardCharsets.UTF_8); // remove any trailing newline actual = actual.trim(); - Assert.assertEquals("sample.dummy:1:\tSampleXPathRule:\tTest Rule 2", actual); + assertThat(actual, containsString("sample.dummy:1:\tSampleXPathRule:\tTest Rule 2")); } } diff --git a/pmd-core/src/test/resources/net/sourceforge/pmd/ant/xml/expected-pmd-ant-xml.xml b/pmd-core/src/test/resources/net/sourceforge/pmd/ant/xml/expected-pmd-ant-xml.xml index 081d871709..705fc08dfa 100644 --- a/pmd-core/src/test/resources/net/sourceforge/pmd/ant/xml/expected-pmd-ant-xml.xml +++ b/pmd-core/src/test/resources/net/sourceforge/pmd/ant/xml/expected-pmd-ant-xml.xml @@ -4,5 +4,8 @@ Test Rule 2 + +Test Rule 3 + diff --git a/pmd-core/src/test/resources/rulesets/dummy/basic.xml b/pmd-core/src/test/resources/rulesets/dummy/basic.xml index e4874941cc..bc9c94cc4a 100644 --- a/pmd-core/src/test/resources/rulesets/dummy/basic.xml +++ b/pmd-core/src/test/resources/rulesets/dummy/basic.xml @@ -47,7 +47,7 @@ Just for test From f567b8caee40580db0005e1669fd4ee090d1e9fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 24 Apr 2022 00:01:51 +0200 Subject: [PATCH 110/180] plsql: Update reference files The SourceCode attribute has disappeared --- .../net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup0.txt | 2 +- .../net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup1.txt | 2 +- .../net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup2.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup0.txt b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup0.txt index cabf4a0f6a..bdb2c702fa 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup0.txt +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup0.txt @@ -1,4 +1,4 @@ -+- Input[@CanonicalImage = null, @ExcludedLinesCount = "0", @ExcludedRangesCount = "0", @Sourcecode = "CREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS\n --\n CURSOR c_example IS\n SELECT a.owner, u.object_name, p.aggregate\n FROM (USER_OBJECTS u) INNER JOIN (ALL_OBJECTS a) ON\n u.object_name = a.object_name AND u.object_type = a.object_type AND u.object_id = a.object_id\n INNER JOIN (ALL_PROCEDURES p) ON\n p.owner = a.owner AND p.object_name = a.object_name AND p.object_type = a.object_type\n WHERE a.owner = USER;\n --\nBEGIN\n --\n FOR l_object IN c_example LOOP\n --\n DBMS_OUTPUT.Put_Line(l_object.owner);\n DBMS_OUTPUT.Put_Line(l_object.object_name);\n DBMS_OUTPUT.Put_Line(l_object.aggregate);\n --\n END LOOP;\n --\nEND EXAMPLE_PROCEDURE;\n"] ++- Input[@CanonicalImage = null, @ExcludedLinesCount = "0", @ExcludedRangesCount = "0"] +- Global[@CanonicalImage = null] +- ProgramUnit[@CanonicalImage = null, @MethodName = "EXAMPLE_PROCEDURE", @Name = "EXAMPLE_PROCEDURE", @ObjectName = null] +- MethodDeclarator[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE", @ParameterCount = "1"] diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup1.txt b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup1.txt index adc310a7b1..48fe75d278 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup1.txt +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup1.txt @@ -1,4 +1,4 @@ -+- Input[@CanonicalImage = null, @ExcludedLinesCount = "0", @ExcludedRangesCount = "0", @Sourcecode = "CREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS\n --\n CURSOR c_example IS\n SELECT a.owner, u.object_name, p.aggregate\n FROM (((USER_OBJECTS u) INNER JOIN (ALL_OBJECTS a) ON\n u.object_name = a.object_name AND u.object_type = a.object_type AND u.object_id = a.object_id)\n INNER JOIN (ALL_PROCEDURES p) ON\n p.owner = a.owner AND p.object_name = a.object_name AND p.object_type = a.object_type)\n WHERE a.owner = USER;\n --\nBEGIN\n --\n FOR l_object IN c_example LOOP\n --\n DBMS_OUTPUT.Put_Line(l_object.owner);\n DBMS_OUTPUT.Put_Line(l_object.object_name);\n DBMS_OUTPUT.Put_Line(l_object.aggregate);\n --\n END LOOP;\n --\nEND EXAMPLE_PROCEDURE;\n"] ++- Input[@CanonicalImage = null, @ExcludedLinesCount = "0", @ExcludedRangesCount = "0"] +- Global[@CanonicalImage = null] +- ProgramUnit[@CanonicalImage = null, @MethodName = "EXAMPLE_PROCEDURE", @Name = "EXAMPLE_PROCEDURE", @ObjectName = null] +- MethodDeclarator[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE", @ParameterCount = "1"] diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup2.txt b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup2.txt index c7e6d1afb5..5dff6521ae 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup2.txt +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup2.txt @@ -1,4 +1,4 @@ -+- Input[@CanonicalImage = null, @ExcludedLinesCount = "0", @ExcludedRangesCount = "0", @Sourcecode = "CREATE OR REPLACE PROCEDURE TEST_PROCEDURE IS\n --\n CURSOR c_test IS\n SELECT si.sid, sn.name, sa.age, ss.score, sp.parent\n FROM ((((STUDENT_INFO si) INNER JOIN (STUDENT_AGE sa) on si.sid = sa.sid)\n INNER JOIN\n (STUDENT_SCORE ss) on si.sid = sp.sid)\n INNER JOIN\n (STUDENT_PARENT sp) on si.sid = sp.sid)\n WHERE si.sid = \'114514\';\n --\nBEGIN\n --\n --\nEND EXAMPLE_PROCEDURE;\n"] ++- Input[@CanonicalImage = null, @ExcludedLinesCount = "0", @ExcludedRangesCount = "0"] +- Global[@CanonicalImage = null] +- ProgramUnit[@CanonicalImage = null, @MethodName = "TEST_PROCEDURE", @Name = "TEST_PROCEDURE", @ObjectName = null] +- MethodDeclarator[@CanonicalImage = "TEST_PROCEDURE", @Image = "TEST_PROCEDURE", @ParameterCount = "1"] From 1da096b126fc4cc1a29e282bf84ce70aafa71d23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 24 Apr 2022 11:50:33 +0200 Subject: [PATCH 111/180] Merge, wip --- .../net/sourceforge/pmd/lang/ast/Node.java | 6 +-- .../pmd/lang/document/BaseMappedDocument.java | 20 +++++++ .../lang/document/FragmentedTextDocument.java | 53 ++++++++++++++----- .../pmd/lang/document/TextDocument.java | 48 ++++++++++++++--- .../pmd/lang/document/TextPos2d.java | 5 ++ .../pmd/lang/document/TextRegion.java | 15 ++---- .../java/net/sourceforge/pmd/ReportTest.java | 5 +- .../pmd/RuleViolationComparatorTest.java | 2 +- .../pmd/renderers/AbstractRendererTest.java | 2 +- .../pmd/renderers/XMLRendererTest.java | 3 +- .../pmd/renderers/XSLTRendererTest.java | 2 +- 11 files changed, 117 insertions(+), 44 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/Node.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/Node.java index 7d71a83c62..58860b614e 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 @@ -130,12 +130,8 @@ public interface Node extends Reportable { * to create a region. */ default TextRegion getTextRegion() { - @SuppressWarnings("PMD.CloseResource") - TextDocument document = getAstInfo().getTextDocument(); FileLocation loc = getReportLocation(); - int startOffset = document.offsetAtLineColumn(loc.getStartPos()); - int endOffset = document.offsetAtLineColumn(loc.getStartPos()); - return TextRegion.fromBothOffsets(startOffset, endOffset); + return getAstInfo().getTextDocument().toRegion(loc.toRange2d()); } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/BaseMappedDocument.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/BaseMappedDocument.java index b25d6aaf33..cbea8633d8 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/BaseMappedDocument.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/BaseMappedDocument.java @@ -59,6 +59,21 @@ abstract class BaseMappedDocument implements TextDocument { return base.createLineRange(startLineInclusive, endLineInclusive); } + @Override + public int offsetAtLineColumn(int line, int column) { + throw new UnsupportedOperationException(); + } + + @Override + public TextPos2d lineColumnAtOffset(int offset, boolean inclusive) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isInRange(TextPos2d textPos2d) { + return false; + } + @Override public int inputOffset(int outOffset, boolean inclusive) { if (outOffset < 0 || outOffset > getLength()) { @@ -67,8 +82,13 @@ abstract class BaseMappedDocument implements TextDocument { return base.inputOffset(localOffsetTransform(outOffset, inclusive), inclusive); } + /** + * Output offset to input offset. + */ protected abstract int localOffsetTransform(int outOffset, boolean inclusive); + protected abstract int inverseLocalOffsetTransform(int inOffset, boolean inclusive); + @Override public void close() throws IOException { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/FragmentedTextDocument.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/FragmentedTextDocument.java index 735c7aa2a3..99be79f6df 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/FragmentedTextDocument.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/FragmentedTextDocument.java @@ -4,6 +4,8 @@ package net.sourceforge.pmd.lang.document; +import java.util.function.ToIntFunction; + import org.checkerframework.checker.nullness.qual.Nullable; import net.sourceforge.pmd.lang.LanguageVersion; @@ -48,44 +50,71 @@ final class FragmentedTextDocument extends BaseMappedDocument implements TextDoc @Override protected int localOffsetTransform(int outOffset, boolean inclusive) { - return inputOffsetAt(outOffset, inclusive); + return offsetTransform(outOffset, inclusive, + Fragment::outToIn, + Fragment::outEnd, + Fragment::outStart + ); } - private int inputOffsetAt(int outputOffset, boolean inclusive) { + @Override + protected int inverseLocalOffsetTransform(int inOffset, boolean inclusive) { + return offsetTransform(inOffset, inclusive, + Fragment::inToOut, + Fragment::inEnd, + Fragment::inStart + ); + } + + interface OffsetMapper { + + int mapOffset(Fragment fragment, int offset); + } + + private int offsetTransform(int offset, + boolean inclusive, + OffsetMapper mapOffsetWhenContains, + ToIntFunction end, + ToIntFunction start) { // caching the last accessed fragment instead of doing // a linear search is critical for performance. Fragment f = this.lastAccessedFragment; if (f == null) { - return outputOffset; + return offset; } - if (!f.contains(outputOffset)) { + // Whether the fragment contains the offset we're looking for. + // Will be true most of the time. + boolean containsOffset = + start.applyAsInt(f) >= offset && offset < end.applyAsInt(f); + + if (!containsOffset) { // Slow path, we must search for the fragment // This optimisation is important, otherwise we have // to search for very long times in some files - if (f.outEnd() < outputOffset) { // search forward - while (f.next != null && f.outEnd() < outputOffset) { + if (end.applyAsInt(f) < offset) { // search forward + while (f.next != null && end.applyAsInt(f) < offset) { f = f.next; } } else { // search backwards - while (f.prev != null && outputOffset <= f.outStart()) { + while (f.prev != null && offset <= start.applyAsInt(f)) { f = f.prev; } } lastAccessedFragment = f; } - if (!inclusive && f.outEnd() == outputOffset) { + if (!inclusive && end.applyAsInt(f) == offset) { if (f.next != null) { f = f.next; lastAccessedFragment = f; // fallthrough } else { - return f.outToIn(outputOffset) + 1; + return mapOffsetWhenContains.mapOffset(f, offset) + 1; } } - return f.outToIn(outputOffset); + return mapOffsetWhenContains.mapOffset(f, offset); } @@ -150,8 +179,8 @@ final class FragmentedTextDocument extends BaseMappedDocument implements TextDoc return inStart() + outOffset - outStart(); } - boolean contains(int outOffset) { - return outStart() <= outOffset && outEnd() > outOffset; + int inToOut(int inOffset) { + return inOffset - inStart() + outStart(); } @Override diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextDocument.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextDocument.java index e7fe94c960..10d5209fde 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextDocument.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextDocument.java @@ -148,7 +148,7 @@ public interface TextDocument extends Closeable { int inputOffset(int outOffset, boolean inclusive); /** - * Translate a region given in the the coordinate system of this + * Translate a region given in the coordinate system of this * document, to the coordinate system of the original document. * This works as if creating a new region with both start and end * offsets translated through {@link #inputOffset(int, boolean)}. The @@ -160,6 +160,21 @@ public interface TextDocument extends Closeable { */ TextRegion inputRegion(TextRegion outputRegion); + /** + * Translate a 2D range given in the coordinate system of this + * document, to the coordinate system of the original document. + * This works as if creating a new region with both start and end + * offsets translated through {@link #inputOffset(int, boolean)}. The + * returned region may have a different length. + * + * @param outputRange Output region + * + * @return Input region + */ + default TextRange2d inputRange(TextRange2d outputRange) { + return toRange2d(inputRegion(toRegion(outputRange))); + } + /** * Returns a reader over the text of this document. @@ -176,16 +191,20 @@ public interface TextDocument extends Closeable { } /** - * Returns a text region that corresponds to the entire document. + * Returns a text region that corresponds to the entire document, + * in the coordinate system of this document. */ default TextRegion getEntireRegion() { return TextRegion.fromOffsetLength(0, getLength()); } /** - * Returns a 2D text range that corresponds to the entire document. + * Returns a 2D text range that corresponds to the entire document, + * in the coordinate system of this document. */ - TextRange2d getEntireRegion2d(); + default TextRange2d getEntireRegion2d() { + return toRange2d(getEntireRegion()); + } /** * Returns a region that spans the text of all the given lines. @@ -210,7 +229,9 @@ public interface TextDocument extends Closeable { * the line/column information for both start and end offset of * the region. * - * @return A new file position + * @param region A region, in the coordinate system of this document + * + * @return A new file position, with absolute coordinates * * @throws IndexOutOfBoundsException If the argument is not a valid region in this document */ @@ -231,7 +252,7 @@ public interface TextDocument extends Closeable { } TextRegion region = TextRegion.caretAt(startOffset); checkInRange(region, this.getLength()); - return FileLocation.location(getDisplayName(), range); + return FileLocation.range(getDisplayName(), range); } /** @@ -289,6 +310,8 @@ public interface TextDocument extends Closeable { /** * Returns the line and column at the given offset (inclusive). + * Both the input offset and the output range are in the coordinates + * of this document. * * @param offset A source offset (0-based), can range in {@code [0, length]}. * @param inclusive If the offset falls right after a line terminator, @@ -296,6 +319,8 @@ public interface TextDocument extends Closeable { * choose the position at the start of the next line. * Otherwise choose the offset at the end of the line. * + * @return A position, in the coordinate system of this document + * * @throws IndexOutOfBoundsException if the offset is out of bounds */ TextPos2d lineColumnAtOffset(int offset, boolean inclusive); @@ -315,6 +340,17 @@ public interface TextDocument extends Closeable { @Override void close() throws IOException; + /** + * Create a new text document for the given text file. The document's + * coordinate system is the same as the original text file. + * + * @param textFile A text file + * + * @return A new text document + * + * @throws IOException If the file cannot be read ({@link TextFile#readContents()}) + * @throws NullPointerException If the parameter is null + */ static TextDocument create(TextFile textFile) throws IOException { return new RootTextDocument(textFile); } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextPos2d.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextPos2d.java index bdf767af3b..4f561fb238 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextPos2d.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextPos2d.java @@ -11,6 +11,11 @@ import org.checkerframework.checker.nullness.qual.NonNull; */ public final class TextPos2d implements Comparable { + /** + * The position at the start of the document (line 1, column 1). + */ + public static TextPos2d DOCUMENT_START = new TextPos2d(1, 1); + private final int line; private final int column; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextRegion.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextRegion.java index 5d14a965a2..a8fd7d6956 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextRegion.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextRegion.java @@ -122,8 +122,8 @@ public final class TextRegion implements Comparable { * @throws AssertionError If the parameter cannot produce a valid region */ public TextRegion growLeft(int delta) { - assert (delta + length) >= 0 : "Left delta " + delta + " would produce a negative length region" + parThis(); - assert (startOffset - delta) >= 0 : "Left delta " + delta + " would produce a region that starts before zero" + parThis(); + assert delta + length >= 0 : "Left delta " + delta + " would produce a negative length region" + parThis(); + assert startOffset - delta >= 0 : "Left delta " + delta + " would produce a region that starts before zero" + parThis(); return new TextRegion(startOffset - delta, delta + length); } @@ -135,7 +135,7 @@ public final class TextRegion implements Comparable { * @throws AssertionError If the delta is negative and less than the length of this region */ public TextRegion growRight(int delta) { - assert (delta + length) >= 0 : "Right delta " + delta + " would produce a negative length region" + parThis(); + assert delta + length >= 0 : "Right delta " + delta + " would produce a negative length region" + parThis(); return new TextRegion(startOffset, delta + length); } @@ -181,15 +181,6 @@ public final class TextRegion implements Comparable { return new TextRegion(startOffset, length); } - /** - * Builds a new region from offset and length. - * - * @throws AssertionError If either parameter is negative - */ - public static TextRegion caretAt(int offset) { - return fromOffsetLength(offset, 0); - } - /** * Builds a new region from start and end offset. * diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/ReportTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/ReportTest.java index 3bf7ea5247..f987287f8f 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/ReportTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/ReportTest.java @@ -75,10 +75,7 @@ public class ReportTest { } private static FileLocation getNode(int line, int column, String filename) { - return FileLocation.location( - filename, - TextRange2d.range2d(line, column, line, column) - ); + return FileLocation.range(filename, TextRange2d.range2d(line, column, line, column)); } public static String render(Renderer renderer, Consumer listenerEffects) throws IOException { diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/RuleViolationComparatorTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/RuleViolationComparatorTest.java index 84c00c96a3..cbfa83b685 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/RuleViolationComparatorTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/RuleViolationComparatorTest.java @@ -70,7 +70,7 @@ public class RuleViolationComparatorTest { private RuleViolation createJavaRuleViolation(Rule rule, String fileName, int beginLine, String description, int beginColumn, int endLine, int endColumn) { - FileLocation loc = FileLocation.location(fileName, TextRange2d.range2d(beginLine, beginColumn, endLine, endColumn)); + FileLocation loc = FileLocation.range(fileName, TextRange2d.range2d(beginLine, beginColumn, endLine, endColumn)); return new ParametricRuleViolation(rule, loc, description); } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/AbstractRendererTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/AbstractRendererTest.java index 98b2b5a017..a61b2c0066 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/AbstractRendererTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/AbstractRendererTest.java @@ -92,7 +92,7 @@ public abstract class AbstractRendererTest { protected FileLocation createLocation(int beginLine, int beginColumn, int endLine, int endColumn) { TextRange2d range2d = TextRange2d.range2d(beginLine, beginColumn, endLine, endColumn); - return FileLocation.location(getSourceCodeFilename(), range2d); + return FileLocation.range(getSourceCodeFilename(), range2d); } protected RuleViolation newRuleViolation(int beginLine, int beginColumn, int endLine, int endColumn, Rule rule) { diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/XMLRendererTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/XMLRendererTest.java index 8cbe58a269..2ea3e05434 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/XMLRendererTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/XMLRendererTest.java @@ -91,8 +91,7 @@ public class XMLRendererTest extends AbstractRendererTest { } private RuleViolation createRuleViolation(String description) { - FileLocation loc = FileLocation.location(getSourceCodeFilename(), - TextRange2d.range2d(1, 1, 1, 1)); + FileLocation loc = FileLocation.range(getSourceCodeFilename(), TextRange2d.range2d(1, 1, 1, 1)); return new ParametricRuleViolation(new FooRule(), loc, description); } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/XSLTRendererTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/XSLTRendererTest.java index a376586054..48ac7089b9 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/XSLTRendererTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/XSLTRendererTest.java @@ -19,7 +19,7 @@ public class XSLTRendererTest { @Test public void testDefaultStylesheet() throws Exception { XSLTRenderer renderer = new XSLTRenderer(); - FileLocation loc = FileLocation.location("file", TextRange2d.range2d(1, 1, 1, 2)); + FileLocation loc = FileLocation.range("file", TextRange2d.range2d(1, 1, 1, 2)); RuleViolation rv = new ParametricRuleViolation(new FooRule(), loc, "violation message"); String result = ReportTest.render(renderer, it -> it.onRuleViolation(rv)); Assert.assertTrue(result.contains("violation message")); From fa60ad93177b77177219d5bcd4561b3dbe1b006f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 24 Apr 2022 11:53:16 +0200 Subject: [PATCH 112/180] Cleanup tests Make DummyNode use offset/length coordinates --- .../java/net/sourceforge/pmd/RuleContext.java | 2 +- .../pmd/cache/CachedRuleViolation.java | 2 +- .../pmd/lang/document/FileLocation.java | 2 +- .../pmd/lang/document/TextDocument.java | 2 +- .../pmd/lang/document/TextRange2d.java | 10 ++++ .../java/net/sourceforge/pmd/ReportTest.java | 2 +- .../pmd/RuleViolationComparatorTest.java | 2 +- .../sourceforge/pmd/RuleViolationTest.java | 22 ++++----- .../pmd/cache/FileAnalysisCacheTest.java | 2 +- .../token/internal/BaseTokenFilterTest.java | 3 +- .../pmd/lang/DummyLanguageModule.java | 15 ++---- .../sourceforge/pmd/lang/ast/DummyNode.java | 46 +++++++------------ .../lang/ast/DummyNodeWithListAndEnum.java | 4 +- .../pmd/lang/rule/XPathRuleTest.java | 3 +- .../xpath/impl/AttributeAxisIteratorTest.java | 1 - .../rule/xpath/internal/ElementNodeTest.java | 16 +++---- .../pmd/renderers/AbstractRendererTest.java | 2 +- .../pmd/renderers/XMLRendererTest.java | 4 +- .../pmd/renderers/XSLTRendererTest.java | 2 +- .../pmd/ant/xml/expected-pmd-ant-xml.xml | 6 +-- .../pmd/lang/java/ast/JavadocElement.java | 2 +- .../pmd/test/lang/ast/DummyNode.java | 2 +- 22 files changed, 69 insertions(+), 83 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/RuleContext.java b/pmd-core/src/main/java/net/sourceforge/pmd/RuleContext.java index c8a700d2a1..a9875bde60 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/RuleContext.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/RuleContext.java @@ -132,7 +132,7 @@ public final class RuleContext { FileLocation location = node.getReportLocation(); if (beginLine != -1 && endLine != -1) { - location = FileLocation.location(location.getFileName(), TextRange2d.range2d(beginLine, 1, endLine, 1)); + location = FileLocation.range(location.getFileName(), TextRange2d.range2d(beginLine, 1, endLine, 1)); } RuleViolation violation = fact.createViolation(rule, node, location, makeMessage(message, formatArgs)); diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cache/CachedRuleViolation.java b/pmd-core/src/main/java/net/sourceforge/pmd/cache/CachedRuleViolation.java index de24b675c4..d5abbe3047 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/cache/CachedRuleViolation.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/cache/CachedRuleViolation.java @@ -42,7 +42,7 @@ public final class CachedRuleViolation implements RuleViolation { final String className, final String methodName, final String variableName) { this.mapper = mapper; this.description = description; - this.location = FileLocation.location(fileName, TextRange2d.range2d(beginLine, beginColumn, endLine, endColumn)); + this.location = FileLocation.range(fileName, TextRange2d.range2d(beginLine, beginColumn, endLine, endColumn)); this.ruleClassName = ruleClassName; this.ruleName = ruleName; this.ruleTargetLanguage = ruleTargetLanguage; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/FileLocation.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/FileLocation.java index 498a9e15a4..31b0482b5a 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/FileLocation.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/FileLocation.java @@ -145,7 +145,7 @@ public final class FileLocation { * @throws IllegalArgumentException If the line and column are not correctly ordered * @throws IllegalArgumentException If the start offset or length are negative */ - public static FileLocation location(String fileName, TextRange2d range2d) { + public static FileLocation range(String fileName, TextRange2d range2d) { TextPos2d start = range2d.getStartPos(); TextPos2d end = range2d.getEndPos(); return new FileLocation(fileName, diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextDocument.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextDocument.java index 6c6f95b48c..4a7cbed4f4 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextDocument.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextDocument.java @@ -163,7 +163,7 @@ public interface TextDocument extends Closeable { } TextRegion region = TextRegion.caretAt(startOffset); checkInRange(region, this.getLength()); - return FileLocation.location(getDisplayName(), range); + return FileLocation.range(getDisplayName(), range); } /** diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextRange2d.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextRange2d.java index fb7be6d919..c60eb1a5c5 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextRange2d.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextRange2d.java @@ -17,12 +17,22 @@ public final class TextRange2d implements Comparable { private final int endCol; public TextRange2d(int startLine, int startCol, int endLine, int endCol) { + checkValid(startLine, startCol, endLine, endCol); this.startLine = startLine; this.startCol = startCol; this.endLine = endLine; this.endCol = endCol; } + private void checkValid(int startLine, int startCol, int endLine, int endCol) { + if (startCol < 1 || startLine < 1 || endLine < 1 || endCol < 1) { + throw new IllegalArgumentException( + "Not a valid range (l" + startLine + ", c" + startCol + ")-" + + "(l" + endLine + ", c" + endCol + ")" + ); + } + } + public TextPos2d getStartPos() { return TextPos2d.pos2d(startLine, startCol); diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/ReportTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/ReportTest.java index 3bf7ea5247..7e436ae89f 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/ReportTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/ReportTest.java @@ -75,7 +75,7 @@ public class ReportTest { } private static FileLocation getNode(int line, int column, String filename) { - return FileLocation.location( + return FileLocation.range( filename, TextRange2d.range2d(line, column, line, column) ); diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/RuleViolationComparatorTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/RuleViolationComparatorTest.java index 84c00c96a3..cbfa83b685 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/RuleViolationComparatorTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/RuleViolationComparatorTest.java @@ -70,7 +70,7 @@ public class RuleViolationComparatorTest { private RuleViolation createJavaRuleViolation(Rule rule, String fileName, int beginLine, String description, int beginColumn, int endLine, int endColumn) { - FileLocation loc = FileLocation.location(fileName, TextRange2d.range2d(beginLine, beginColumn, endLine, endColumn)); + FileLocation loc = FileLocation.range(fileName, TextRange2d.range2d(beginLine, beginColumn, endLine, endColumn)); return new ParametricRuleViolation(rule, loc, description); } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/RuleViolationTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/RuleViolationTest.java index 468e9537ad..5036f52e3d 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/RuleViolationTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/RuleViolationTest.java @@ -9,12 +9,14 @@ import static org.junit.Assert.assertTrue; import java.util.Comparator; -import org.junit.Ignore; import org.junit.Test; import net.sourceforge.pmd.lang.DummyLanguageModule; import net.sourceforge.pmd.lang.ast.DummyNode; import net.sourceforge.pmd.lang.ast.DummyNode.DummyRootNode; +import net.sourceforge.pmd.lang.document.FileLocation; +import net.sourceforge.pmd.lang.document.TextFile; +import net.sourceforge.pmd.lang.document.TextRange2d; import net.sourceforge.pmd.lang.rule.MockRule; import net.sourceforge.pmd.lang.rule.ParametricRuleViolation; @@ -68,25 +70,19 @@ public class RuleViolationTest { assertTrue(comp.compare(r2, r1) > 0); } - @Ignore("FIXME enabling this test means we don't respect the contract of Comparator!") @Test public void testComparatorWithSameFileSameLines() { Rule rule = new MockRule("name", "desc", "msg", "rulesetname"); Comparator comp = RuleViolation.DEFAULT_COMPARATOR; - DummyRootNode rootNode = new DummyRootNode(); + String filename = TextFile.UNKNOWN_FILENAME; - DummyNode s = new DummyNode(); - s.setCoords(10, 1, 15, 10); - rootNode.addChild(s, 0); - RuleViolation r1 = new ParametricRuleViolation(rule, s, "description"); - DummyNode s1 = new DummyNode(); - s1.setCoords(10, 1, 15, 10); - rootNode.addChild(s1, 1); - RuleViolation r2 = new ParametricRuleViolation(rule, s1, "description"); + FileLocation loc = FileLocation.range(filename, TextRange2d.range2d(10, 1, 15, 10)); + RuleViolation r1 = new ParametricRuleViolation(rule, loc, "description"); + RuleViolation r2 = new ParametricRuleViolation(rule, loc, "description"); - assertEquals(1, comp.compare(r1, r2)); - assertEquals(1, comp.compare(r2, r1)); + assertEquals(0, comp.compare(r1, r2)); + assertEquals(0, comp.compare(r2, r1)); } public static junit.framework.Test suite() { diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/cache/FileAnalysisCacheTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/cache/FileAnalysisCacheTest.java index a197ba9251..3ca761e9b4 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/cache/FileAnalysisCacheTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/cache/FileAnalysisCacheTest.java @@ -117,7 +117,7 @@ public class FileAnalysisCacheTest { final RuleViolation rv = mock(RuleViolation.class); when(rv.getFilename()).thenReturn(sourceFile.getDisplayName()); - when(rv.getLocation()).thenReturn(FileLocation.location(sourceFile.getDisplayName(), TextRange2d.range2d(1, 2, 3, 4))); + when(rv.getLocation()).thenReturn(FileLocation.range(sourceFile.getDisplayName(), TextRange2d.range2d(1, 2, 3, 4))); final net.sourceforge.pmd.Rule rule = mock(net.sourceforge.pmd.Rule.class, Mockito.RETURNS_SMART_NULLS); when(rule.getLanguage()).thenReturn(mock(Language.class)); when(rv.getRule()).thenReturn(rule); 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 b8d15b7cae..5e4374433c 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 @@ -19,6 +19,7 @@ import org.junit.Test; import net.sourceforge.pmd.lang.TokenManager; import net.sourceforge.pmd.lang.ast.GenericToken; import net.sourceforge.pmd.lang.document.FileLocation; +import net.sourceforge.pmd.lang.document.TextFile; import net.sourceforge.pmd.lang.document.TextRange2d; import net.sourceforge.pmd.lang.document.TextRegion; @@ -59,7 +60,7 @@ public class BaseTokenFilterTest { @Override public FileLocation getReportLocation() { - return FileLocation.location("n/a", TextRange2d.range2d(0, 0, 0, 0)); + return FileLocation.range(TextFile.UNKNOWN_FILENAME, TextRange2d.range2d(1, 1, 1, 1)); } @Override diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/DummyLanguageModule.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/DummyLanguageModule.java index 15f94eb42e..67ea0b3513 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/DummyLanguageModule.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/DummyLanguageModule.java @@ -20,8 +20,6 @@ import net.sourceforge.pmd.lang.document.Chars; import net.sourceforge.pmd.lang.document.FileLocation; import net.sourceforge.pmd.lang.document.TextDocument; import net.sourceforge.pmd.lang.document.TextFile; -import net.sourceforge.pmd.lang.document.TextPos2d; -import net.sourceforge.pmd.lang.document.TextRange2d; import net.sourceforge.pmd.lang.document.TextRegion; import net.sourceforge.pmd.lang.rule.ParametricRuleViolation; import net.sourceforge.pmd.lang.rule.impl.DefaultRuleViolationFactory; @@ -115,14 +113,11 @@ public class DummyLanguageModule extends BaseLanguageModule { private static DummyRootNode readLispNode(ParserTask task) { TextDocument document = task.getTextDocument(); final DummyRootNode root = new DummyRootNode().withTaskInfo(task); - { - TextPos2d endPos = document.getEntireRegion2d().getEndPos(); - root.setCoords(1, 1, endPos.getLine(), endPos.getColumn()); - } + root.setRegion(document.getEntireRegion()); DummyNode top = root; int lastNodeStart = 0; - Chars text = document.getContent().getNormalizedText(); + Chars text = document.getText(); for (int i = 0; i < text.length(); i++) { char c = text.charAt(i); if (c == '(') { @@ -130,7 +125,7 @@ public class DummyLanguageModule extends BaseLanguageModule { node.setParent(top); top.addChild(node, top.getNumChildren()); // setup coordinates, temporary (will be completed when node closes) - node.setCoords(document, TextRegion.caretAt(i)); + node.setRegion(TextRegion.caretAt(i)); // cut out image if (top.getImage() == null) { @@ -148,9 +143,7 @@ public class DummyLanguageModule extends BaseLanguageModule { throw new ParseException("Unbalanced parentheses: " + text); } - TextPos2d endPos = document.toRange2d(TextRegion.caretAt(i)).getEndPos(); - TextPos2d startPos = top.getCoords().getStartPos(); - top.setCoords(TextRange2d.range2d(startPos, endPos)); + top.setRegion(TextRegion.fromBothOffsets(top.getTextRegion().getStartOffset(), i)); if (top.getImage() == null) { // cut out image (if node doesn't have children it hasn't been populated yet) diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/DummyNode.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/DummyNode.java index ed94e8ccc2..1fc2150dfe 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/DummyNode.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/DummyNode.java @@ -5,12 +5,12 @@ package net.sourceforge.pmd.lang.ast; import java.util.ArrayList; -import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Objects; +import net.sourceforge.pmd.internal.util.AssertionUtil; import net.sourceforge.pmd.lang.DummyLanguageModule; import net.sourceforge.pmd.lang.ast.Parser.ParserTask; import net.sourceforge.pmd.lang.ast.impl.AbstractNode; @@ -18,22 +18,17 @@ import net.sourceforge.pmd.lang.ast.impl.GenericNode; import net.sourceforge.pmd.lang.document.FileLocation; import net.sourceforge.pmd.lang.document.TextDocument; import net.sourceforge.pmd.lang.document.TextFile; -import net.sourceforge.pmd.lang.document.TextRange2d; import net.sourceforge.pmd.lang.document.TextRegion; import net.sourceforge.pmd.lang.rule.xpath.Attribute; public class DummyNode extends AbstractNode implements GenericNode { private final boolean findBoundary; - private final String xpathName; - private final Map userData = new HashMap<>(); + private String xpathName; private String image; private final List attributes = new ArrayList<>(); - private int bline = 1; - private int bcol = 1; - private int eline = 1; - private int ecol = 1; + private TextRegion region = TextRegion.caretAt(0); public DummyNode(String xpathName) { this(false, xpathName); @@ -83,34 +78,29 @@ public class DummyNode extends AbstractNode implements Gen } } - public DummyNode setCoords(int bline, int bcol, int eline, int ecol) { - this.bline = bline; - this.bcol = bcol; - this.eline = eline; - this.ecol = ecol; - return this; + @Override + public TextRegion getTextRegion() { + return region; } - public DummyNode setCoords(TextDocument document, TextRegion region) { - FileLocation loc = document.toLocation(region); - return setCoords(loc.getStartLine(), loc.getStartColumn(), loc.getEndLine(), loc.getEndColumn()); - } - - public DummyNode setCoords(TextRange2d region) { - return setCoords(region.getStartLine(), region.getStartColumn(), region.getEndLine(), region.getEndColumn()); - } - - public TextRange2d getCoords() { - return TextRange2d.range2d(bline, bcol, eline, ecol); + public void setRegion(TextRegion region) { + this.region = region; } @Override public FileLocation getReportLocation() { - return getTextDocument().toLocation(TextRange2d.range2d(bline, bcol, eline, ecol)); + return getTextDocument().toLocation(region); } + /** + * Nodes with an image that starts with `#` also set the xpath name. + */ public void setImage(String image) { this.image = image; + if (image.startsWith("#")) { + xpathName = image.substring(1); + assert AssertionUtil.isJavaIdentifier(xpathName) : "need an ident after '#': " + image; + } } @Override @@ -133,10 +123,6 @@ public class DummyNode extends AbstractNode implements Gen return findBoundary; } - public Map getUserData() { - return userData; - } - public void setXPathAttribute(String name, String value) { attributes.add(new Attribute(this, name, value)); } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/DummyNodeWithListAndEnum.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/DummyNodeWithListAndEnum.java index e5f0ae9ec2..151037aaac 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/DummyNodeWithListAndEnum.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/DummyNodeWithListAndEnum.java @@ -8,10 +8,12 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import net.sourceforge.pmd.lang.document.TextRegion; + public class DummyNodeWithListAndEnum extends DummyNode.DummyRootNode { public DummyNodeWithListAndEnum() { super(); - setCoords(1, 1, 1, 2); + setRegion(TextRegion.fromOffsetLength(0, 1)); } public enum MyEnum { diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/XPathRuleTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/XPathRuleTest.java index cd58a5e244..4344559685 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/XPathRuleTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/XPathRuleTest.java @@ -20,6 +20,7 @@ import net.sourceforge.pmd.lang.LanguageRegistry; import net.sourceforge.pmd.lang.ast.DummyNode; import net.sourceforge.pmd.lang.ast.DummyNode.DummyRootNode; import net.sourceforge.pmd.lang.ast.DummyNodeWithDeprecatedAttribute; +import net.sourceforge.pmd.lang.document.TextRegion; import net.sourceforge.pmd.lang.rule.xpath.XPathVersion; public class XPathRuleTest { @@ -151,7 +152,7 @@ public class XPathRuleTest { DummyRootNode root = new DummyRootNode(); DummyNode dummy = new DummyNodeWithDeprecatedAttribute(); root.addChild(dummy, 0); - dummy.setCoords(1, 1, 1, 2); + dummy.setRegion(TextRegion.fromOffsetLength(0, 1)); return root; } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/impl/AttributeAxisIteratorTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/impl/AttributeAxisIteratorTest.java index ca9f6d8811..d970f8aeeb 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/impl/AttributeAxisIteratorTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/impl/AttributeAxisIteratorTest.java @@ -36,7 +36,6 @@ public class AttributeAxisIteratorTest { @Test public void testAttributeAxisIterator() { DummyNode dummyNode = new DummyNode(); - dummyNode.setCoords(1, 1, 2, 2); AttributeAxisIterator it = new AttributeAxisIterator(dummyNode); diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/internal/ElementNodeTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/internal/ElementNodeTest.java index 30283b683b..1d15739995 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/internal/ElementNodeTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/internal/ElementNodeTest.java @@ -8,6 +8,7 @@ package net.sourceforge.pmd.lang.rule.xpath.internal; import org.junit.Assert; import org.junit.Test; +import net.sourceforge.pmd.lang.DummyLanguageModule; import net.sourceforge.pmd.lang.ast.DummyNode; import net.sourceforge.pmd.lang.ast.DummyNode.DummyRootNode; @@ -19,16 +20,13 @@ public class ElementNodeTest { @Test public void testCompareOrder() { - DummyRootNode root = new DummyRootNode(); - - DummyNode c0 = new DummyNode(false, "foo"); - c0.setCoords(1, 1, 2, 2); - root.addChild(c0, 0); - - DummyNode c1 = new DummyNode(false, "foo"); - c1.setCoords(2, 1, 2, 2); - root.addChild(c1, 1); + DummyRootNode root = DummyLanguageModule.parse( + "(#foo)" + + "(#foo)" + ); + DummyNode c0 = root.getChild(0); + DummyNode c1 = root.getChild(1); Configuration configuration = Configuration.newConfiguration(); diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/AbstractRendererTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/AbstractRendererTest.java index 98b2b5a017..a61b2c0066 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/AbstractRendererTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/AbstractRendererTest.java @@ -92,7 +92,7 @@ public abstract class AbstractRendererTest { protected FileLocation createLocation(int beginLine, int beginColumn, int endLine, int endColumn) { TextRange2d range2d = TextRange2d.range2d(beginLine, beginColumn, endLine, endColumn); - return FileLocation.location(getSourceCodeFilename(), range2d); + return FileLocation.range(getSourceCodeFilename(), range2d); } protected RuleViolation newRuleViolation(int beginLine, int beginColumn, int endLine, int endColumn, Rule rule) { diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/XMLRendererTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/XMLRendererTest.java index 8cbe58a269..de887c378b 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/XMLRendererTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/XMLRendererTest.java @@ -91,8 +91,8 @@ public class XMLRendererTest extends AbstractRendererTest { } private RuleViolation createRuleViolation(String description) { - FileLocation loc = FileLocation.location(getSourceCodeFilename(), - TextRange2d.range2d(1, 1, 1, 1)); + FileLocation loc = FileLocation.range(getSourceCodeFilename(), + TextRange2d.range2d(1, 1, 1, 1)); return new ParametricRuleViolation(new FooRule(), loc, description); } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/XSLTRendererTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/XSLTRendererTest.java index a376586054..48ac7089b9 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/XSLTRendererTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/XSLTRendererTest.java @@ -19,7 +19,7 @@ public class XSLTRendererTest { @Test public void testDefaultStylesheet() throws Exception { XSLTRenderer renderer = new XSLTRenderer(); - FileLocation loc = FileLocation.location("file", TextRange2d.range2d(1, 1, 1, 2)); + FileLocation loc = FileLocation.range("file", TextRange2d.range2d(1, 1, 1, 2)); RuleViolation rv = new ParametricRuleViolation(new FooRule(), loc, "violation message"); String result = ReportTest.render(renderer, it -> it.onRuleViolation(rv)); Assert.assertTrue(result.contains("violation message")); diff --git a/pmd-core/src/test/resources/net/sourceforge/pmd/ant/xml/expected-pmd-ant-xml.xml b/pmd-core/src/test/resources/net/sourceforge/pmd/ant/xml/expected-pmd-ant-xml.xml index 705fc08dfa..6e7f517c67 100644 --- a/pmd-core/src/test/resources/net/sourceforge/pmd/ant/xml/expected-pmd-ant-xml.xml +++ b/pmd-core/src/test/resources/net/sourceforge/pmd/ant/xml/expected-pmd-ant-xml.xml @@ -1,10 +1,10 @@ - + - + Test Rule 2 - + Test Rule 3 diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavadocElement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavadocElement.java index 86e9ed268f..e7febf6e5b 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavadocElement.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavadocElement.java @@ -17,7 +17,7 @@ public class JavadocElement extends Comment { public JavadocElement(JavaccToken t, int theBeginLine, int theEndLine, int theBeginColumn, int theEndColumn, JavadocTag theTag) { super(t); this.tag = theTag; - this.reportLoc = FileLocation.location("TODO", TextRange2d.range2d(theBeginLine, theBeginColumn, theEndLine, theEndColumn)); + this.reportLoc = FileLocation.range("TODO", TextRange2d.range2d(theBeginLine, theBeginColumn, theEndLine, theEndColumn)); } public JavadocTag tag() { diff --git a/pmd-test/src/main/java/net/sourceforge/pmd/test/lang/ast/DummyNode.java b/pmd-test/src/main/java/net/sourceforge/pmd/test/lang/ast/DummyNode.java index 7bac3c7e33..dbd049969d 100644 --- a/pmd-test/src/main/java/net/sourceforge/pmd/test/lang/ast/DummyNode.java +++ b/pmd-test/src/main/java/net/sourceforge/pmd/test/lang/ast/DummyNode.java @@ -14,7 +14,7 @@ public class DummyNode extends AbstractNode { private FileLocation location; public void setCoords(int bline, int bcol, int eline, int ecol) { - this.location = FileLocation.location(":dummyFile:", TextRange2d.range2d(bline, bcol, eline, ecol)); + this.location = FileLocation.range(":dummyFile:", TextRange2d.range2d(bline, bcol, eline, ecol)); } @Override From 13d0ddad1be69bdda5f04ebe8068b3f5e9e194b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 24 Apr 2022 12:07:18 +0200 Subject: [PATCH 113/180] Sync with designer, remove range2d --- .../pmd/lang/document/RootTextDocument.java | 10 ---- .../pmd/lang/document/TextDocument.java | 44 ------------------ .../pmd/lang/document/TextDocumentTest.java | 46 ------------------- 3 files changed, 100 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/RootTextDocument.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/RootTextDocument.java index 162830346c..9e8ecbb3a3 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/RootTextDocument.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/RootTextDocument.java @@ -123,16 +123,6 @@ final class RootTextDocument extends BaseCloseable implements TextDocument { return TextRegion.fromBothOffsets(first, last); } - @Override - public TextRange2d getEntireRegion2d() { - SourceCodePositioner positioner = content.getPositioner(); - return TextRange2d.range2d( - 1, 1, - positioner.getLastLine(), - positioner.getLastLineColumn() - ); - } - static void checkInRange(TextRegion region, int length) { if (region.getEndOffset() > length) { throw regionOutOfBounds(region.getStartOffset(), region.getEndOffset(), length); diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextDocument.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextDocument.java index 4a7cbed4f4..d1ded64a4f 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextDocument.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextDocument.java @@ -4,8 +4,6 @@ package net.sourceforge.pmd.lang.document; -import static net.sourceforge.pmd.lang.document.RootTextDocument.checkInRange; - import java.io.Closeable; import java.io.IOException; import java.io.Reader; @@ -119,11 +117,6 @@ public interface TextDocument extends Closeable { return TextRegion.fromOffsetLength(0, getLength()); } - /** - * Returns a 2D text range that corresponds to the entire document. - */ - TextRange2d getEntireRegion2d(); - /** * Returns a region that spans the text of all the given lines. * This is intended to provide a replacement for {@link SourceCode#getSlice(int, int)}. @@ -148,43 +141,6 @@ public interface TextDocument extends Closeable { */ FileLocation toLocation(TextRegion region); - /** - * Turn a text region into a {@link FileLocation}. The file name is - * the display name of this document. - * - * @return A new file position - * - * @throws IndexOutOfBoundsException If the argument is not a valid region in this document - */ - default FileLocation toLocation(TextRange2d range) { - int startOffset = offsetAtLineColumn(range.getStartPos()); - if (startOffset < 0) { - throw new IndexOutOfBoundsException("Region out of bounds: " + range.displayString()); - } - TextRegion region = TextRegion.caretAt(startOffset); - checkInRange(region, this.getLength()); - return FileLocation.range(getDisplayName(), range); - } - - /** - * Turn a text region to a {@link TextRange2d}. - */ - default TextRange2d toRange2d(TextRegion region) { - TextPos2d start = lineColumnAtOffset(region.getStartOffset(), true); - TextPos2d end = lineColumnAtOffset(region.getEndOffset(), false); - return TextRange2d.range2d(start, end); - } - - /** - * Turn a {@link TextRange2d} into a {@link TextRegion}. - */ - default TextRegion toRegion(TextRange2d region) { - return TextRegion.fromBothOffsets( - offsetAtLineColumn(region.getStartPos()), - offsetAtLineColumn(region.getEndPos()) - ); - } - /** * Returns the offset at the given line and column number. diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextDocumentTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextDocumentTest.java index 888fc8760b..22620da346 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextDocumentTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextDocumentTest.java @@ -156,52 +156,6 @@ public class TextDocumentTest { assertEquals(1 + "bonjour".length(), withLines.getEndColumn()); } - @Test - public void testOffsetFromLineColumn() { - TextDocument doc = TextDocument.readOnlyString("bonjour\noa\n", dummyVersion); - - assertEquals(0, doc.offsetAtLineColumn(1, 1)); - assertEquals(1, doc.offsetAtLineColumn(1, 2)); - assertEquals(2, doc.offsetAtLineColumn(1, 3)); - assertEquals(3, doc.offsetAtLineColumn(1, 4)); - assertEquals(4, doc.offsetAtLineColumn(1, 5)); - assertEquals(5, doc.offsetAtLineColumn(1, 6)); - assertEquals(6, doc.offsetAtLineColumn(1, 7)); - assertEquals(7, doc.offsetAtLineColumn(1, 8)); - assertEquals(8, doc.offsetAtLineColumn(1, 9)); - assertEquals(8, doc.offsetAtLineColumn(2, 1)); - assertEquals(9, doc.offsetAtLineColumn(2, 2)); - assertEquals(10, doc.offsetAtLineColumn(2, 3)); - assertEquals(11, doc.offsetAtLineColumn(2, 4)); - assertEquals(11, doc.offsetAtLineColumn(3, 1)); - } - - @Test - public void testCoordinateRoundTripWithEndOfLine() { - TextDocument doc = TextDocument.readOnlyString("bonjour\noa\n", dummyVersion); - TextRange2d inputRange = TextRange2d.fullLine(1, "bonjour\n".length()); - - TextRegion lineRange = doc.createLineRange(1, 1); - TextRegion region = doc.toRegion(inputRange); - - assertEquals(TextRegion.fromOffsetLength(0, "bonjour\n".length()), region); - assertEquals(TextRegion.fromOffsetLength(0, "bonjour\n".length()), lineRange); - TextRange2d roundTrip = doc.toRange2d(region); - assertEquals(inputRange, roundTrip); - - } - - @Test - public void testCoordinateRoundTripSimple() { - TextDocument doc = TextDocument.readOnlyString("bonjour\noa\n", dummyVersion); - TextRange2d inputRange = TextRange2d.fullLine(1, "bonjour".length()); - - TextRegion region = doc.toRegion(inputRange); - assertEquals(TextRegion.fromOffsetLength(0, "bonjour".length()), region); - - TextRange2d roundTrip = doc.toRange2d(region); - assertEquals(inputRange, roundTrip); - } @Test public void testLineRange() { From f2708f4b4ec891d300b99beb255975d9537d77d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 24 Apr 2022 12:22:03 +0200 Subject: [PATCH 114/180] Make Node#getTextRegion non-default Now implementors of Node need an implementation. Implementation of #getReportLocation can be shared --- .../apex/ast/ASTMethodCallExpression.java | 4 +- .../pmd/lang/apex/ast/AbstractApexNode.java | 9 +--- .../pmd/lang/apex/ast/ApexTreeBuilder.java | 2 +- .../net/sourceforge/pmd/lang/ast/Node.java | 16 ++----- .../lang/ast/impl/antlr4/BaseAntlrNode.java | 8 ++-- .../ast/impl/javacc/AbstractJjtreeNode.java | 5 -- .../sourceforge/pmd/lang/ast/DummyNode.java | 5 -- .../java/ast/ASTLocalVariableDeclaration.java | 1 + .../lang/java/ast/ASTMethodDeclaration.java | 1 + .../ast/AbstractEcmascriptNode.java | 6 --- .../pmd/lang/scala/ast/AbstractScalaNode.java | 6 +-- .../pmd/test/lang/DummyLanguageModule.java | 47 +++++++++++-------- .../pmd/test/lang/ast/DummyNode.java | 23 +++++---- .../pmd/testframework/RuleTstTest.java | 14 ++++-- .../lang/xml/ast/internal/XmlNodeWrapper.java | 6 +-- 15 files changed, 70 insertions(+), 83 deletions(-) diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTMethodCallExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTMethodCallExpression.java index acc4cd2f3d..a18aa3ebd2 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTMethodCallExpression.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTMethodCallExpression.java @@ -41,10 +41,10 @@ public final class ASTMethodCallExpression extends AbstractApexNode nameLength) { base = base.growLeft(fullLength - nameLength); } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/AbstractApexNode.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/AbstractApexNode.java index 361d857204..48bf3aa906 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/AbstractApexNode.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/AbstractApexNode.java @@ -10,7 +10,6 @@ import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.ast.AstVisitor; import net.sourceforge.pmd.lang.ast.FileAnalysisException; import net.sourceforge.pmd.lang.ast.impl.AbstractNode; -import net.sourceforge.pmd.lang.document.FileLocation; import net.sourceforge.pmd.lang.document.TextDocument; import net.sourceforge.pmd.lang.document.TextRegion; @@ -57,18 +56,14 @@ abstract class AbstractApexNode extends AbstractNode parent = (AbstractApexNode) getParent(); if (parent == null) { throw new FileAnalysisException("Unable to determine location of " + this); } - region = parent.getRegion(); + region = parent.getTextRegion(); } else { Location loc = node.getLoc(); region = TextRegion.fromBothOffsets(loc.getStartIndex(), loc.getEndIndex()); 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 e67bd65fb6..c0a8b441c8 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 @@ -390,7 +390,7 @@ final class ApexTreeBuilder extends AstVisitor { return; } // find the token, that appears as close as possible before the node - TextRegion nodeRegion = node.getRegion(); + TextRegion nodeRegion = node.getTextRegion(); for (ApexDocTokenLocation comment : commentInfo.docTokenLocations) { if (comment.region.compareTo(nodeRegion) > 0) { // this and all remaining tokens are after the node 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 276ae14ce9..c90e342a97 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 @@ -119,24 +119,16 @@ public interface Node extends Reportable { *

Use this instead of {@link #getBeginColumn()}/{@link #getBeginLine()}, etc. */ @Override - FileLocation getReportLocation(); + default FileLocation getReportLocation() { + return getAstInfo().getTextDocument().toLocation(getTextRegion()); + } /** * Returns a region of text delimiting the node in the underlying * text document. This does not necessarily match the * {@link #getReportLocation() report location}. - * - * @implNote The default implementation uses the {@link #getReportLocation()} - * to create a region. */ - default TextRegion getTextRegion() { - @SuppressWarnings("PMD.CloseResource") - TextDocument document = getAstInfo().getTextDocument(); - FileLocation loc = getReportLocation(); - int startOffset = document.offsetAtLineColumn(loc.getStartPos()); - int endOffset = document.offsetAtLineColumn(loc.getStartPos()); - return TextRegion.fromBothOffsets(startOffset, endOffset); - } + TextRegion getTextRegion(); // Those are kept here because they're handled specially as XPath diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/BaseAntlrNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/BaseAntlrNode.java index 64ab4d32a4..3805dbe8e0 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/BaseAntlrNode.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/BaseAntlrNode.java @@ -12,7 +12,6 @@ import org.antlr.v4.runtime.tree.TerminalNode; import net.sourceforge.pmd.lang.ast.impl.GenericNode; import net.sourceforge.pmd.lang.ast.impl.antlr4.BaseAntlrNode.AntlrToPmdParseTreeAdapter; -import net.sourceforge.pmd.lang.document.FileLocation; import net.sourceforge.pmd.lang.document.TextRegion; import net.sourceforge.pmd.util.DataMap; import net.sourceforge.pmd.util.DataMap.DataKey; @@ -70,11 +69,10 @@ public abstract class BaseAntlrNode, N e public abstract Token getLastAntlrToken(); - @Override - public FileLocation getReportLocation() { - return getTextDocument().toLocation(TextRegion.fromBothOffsets(getFirstAntlrToken().getStartIndex(), - getFirstAntlrToken().getStopIndex())); + public TextRegion getTextRegion() { + return TextRegion.fromBothOffsets(getFirstAntlrToken().getStartIndex(), + getFirstAntlrToken().getStopIndex()); } void setIndexInParent(int indexInParent) { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/javacc/AbstractJjtreeNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/javacc/AbstractJjtreeNode.java index ee3e02fea4..5c7073e4bb 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/javacc/AbstractJjtreeNode.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/javacc/AbstractJjtreeNode.java @@ -59,11 +59,6 @@ public abstract class AbstractJjtreeNode, N e getLastToken().getEndOffset()); } - @Override - public FileLocation getReportLocation() { - return getTextDocument().toLocation(getTextRegion()); - } - @Override public final int compareLocation(Node other) { if (other instanceof JjtreeNode) { diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/DummyNode.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/DummyNode.java index 1fc2150dfe..bf1931f9e9 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/DummyNode.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/DummyNode.java @@ -15,7 +15,6 @@ import net.sourceforge.pmd.lang.DummyLanguageModule; import net.sourceforge.pmd.lang.ast.Parser.ParserTask; import net.sourceforge.pmd.lang.ast.impl.AbstractNode; import net.sourceforge.pmd.lang.ast.impl.GenericNode; -import net.sourceforge.pmd.lang.document.FileLocation; import net.sourceforge.pmd.lang.document.TextDocument; import net.sourceforge.pmd.lang.document.TextFile; import net.sourceforge.pmd.lang.document.TextRegion; @@ -87,10 +86,6 @@ public class DummyNode extends AbstractNode implements Gen this.region = region; } - @Override - public FileLocation getReportLocation() { - return getTextDocument().toLocation(region); - } /** * Nodes with an image that starts with `#` also set the xpath name. diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLocalVariableDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLocalVariableDeclaration.java index 85877548b4..816b6956ff 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLocalVariableDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLocalVariableDeclaration.java @@ -37,6 +37,7 @@ public final class ASTLocalVariableDeclaration extends AbstractJavaNode @Override public @Nullable FileLocation getReportLocation() { + // the first varId return getVarIds().firstOrThrow().getFirstToken().getReportLocation(); } 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 2d779175fd..3a83204420 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 @@ -84,6 +84,7 @@ public final class ASTMethodDeclaration extends AbstractMethodOrConstructorDecla @Override public FileLocation getReportLocation() { + // the method identifier JavaccToken ident = TokenUtils.nthPrevious(getModifiers().getLastToken(), getFormalParameters().getFirstToken(), 1); return ident.getReportLocation(); } diff --git a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/AbstractEcmascriptNode.java b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/AbstractEcmascriptNode.java index 05b5f12370..90a0f0a51d 100644 --- a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/AbstractEcmascriptNode.java +++ b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/AbstractEcmascriptNode.java @@ -8,7 +8,6 @@ import org.mozilla.javascript.ast.AstNode; import net.sourceforge.pmd.lang.ast.AstVisitor; import net.sourceforge.pmd.lang.ast.impl.AbstractNode; -import net.sourceforge.pmd.lang.document.FileLocation; import net.sourceforge.pmd.lang.document.TextRegion; abstract class AbstractEcmascriptNode extends AbstractNode, EcmascriptNode> implements EcmascriptNode { @@ -34,11 +33,6 @@ abstract class AbstractEcmascriptNode extends AbstractNode extends AbstractNode { - DummyRootNode node = new DummyRootNode(); - node.setCoords(1, 1, 1, 2); - node.setLanguageVersion(task.getLanguageVersion()); - node.setImage("Foo"); - return node; - }; + return DummyRootNode::new; } } public static class DummyRootNode extends DummyNode implements RootNode { - private LanguageVersion languageVersion = LanguageRegistry.findLanguageByTerseName(DummyLanguageModule.TERSE_NAME).getDefaultVersion(); + private final AstInfo astInfo; - public void setLanguageVersion(LanguageVersion languageVersion) { - this.languageVersion = languageVersion; + public DummyRootNode(ParserTask task) { + this.astInfo = new AstInfo<>(task, this); + withCoords(task.getTextDocument().getEntireRegion()); + setImage("Foo"); } - public DummyRootNode withCoords(int bline, int bcol, int eline, int ecol) { - super.setCoords(bline, bcol, eline, ecol); + @Override + public DummyRootNode withCoords(TextRegion region) { + super.withCoords(region); return this; } @Override public AstInfo getAstInfo() { - return new AstInfo<>( - TextDocument.readOnlyString("dummy text", "sample.dummy", languageVersion), - this, - Collections.emptyMap() - ); + return astInfo; } } diff --git a/pmd-test/src/main/java/net/sourceforge/pmd/test/lang/ast/DummyNode.java b/pmd-test/src/main/java/net/sourceforge/pmd/test/lang/ast/DummyNode.java index dbd049969d..a7e124e100 100644 --- a/pmd-test/src/main/java/net/sourceforge/pmd/test/lang/ast/DummyNode.java +++ b/pmd-test/src/main/java/net/sourceforge/pmd/test/lang/ast/DummyNode.java @@ -4,23 +4,30 @@ package net.sourceforge.pmd.test.lang.ast; +import java.util.Objects; + import net.sourceforge.pmd.lang.ast.impl.AbstractNode; -import net.sourceforge.pmd.lang.document.FileLocation; -import net.sourceforge.pmd.lang.document.TextRange2d; +import net.sourceforge.pmd.lang.document.TextRegion; public class DummyNode extends AbstractNode { private String image; - private FileLocation location; + private TextRegion region = TextRegion.caretAt(0); - public void setCoords(int bline, int bcol, int eline, int ecol) { - this.location = FileLocation.range(":dummyFile:", TextRange2d.range2d(bline, bcol, eline, ecol)); + public DummyNode withCoords(TextRegion region) { + this.region = Objects.requireNonNull(region); + return this; + } + + public DummyNode newChild() { + DummyNode child = new DummyNode(); + addChild(child, getNumChildren()); + return child; } @Override - public FileLocation getReportLocation() { - assert location != null : "Should have called setCoords"; - return location; + public TextRegion getTextRegion() { + return region; } @Deprecated diff --git a/pmd-test/src/test/java/net/sourceforge/pmd/testframework/RuleTstTest.java b/pmd-test/src/test/java/net/sourceforge/pmd/testframework/RuleTstTest.java index 9f54633ced..21c2b065c5 100644 --- a/pmd-test/src/test/java/net/sourceforge/pmd/testframework/RuleTstTest.java +++ b/pmd-test/src/test/java/net/sourceforge/pmd/testframework/RuleTstTest.java @@ -20,6 +20,7 @@ import net.sourceforge.pmd.RuleContext; import net.sourceforge.pmd.lang.LanguageRegistry; import net.sourceforge.pmd.lang.LanguageVersion; import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.document.TextRegion; import net.sourceforge.pmd.lang.rule.RuleTargetSelector; import net.sourceforge.pmd.test.lang.DummyLanguageModule.DummyRootNode; @@ -59,17 +60,22 @@ public class RuleTstTest { when(rule.getTargetSelector()).thenReturn(RuleTargetSelector.forRootOnly()); when(rule.deepCopy()).thenReturn(rule); + final String code = "the\ncode"; Mockito.doAnswer(invocation -> { RuleContext context = invocation.getArgument(1, RuleContext.class); + DummyRootNode node = invocation.getArgument(0, DummyRootNode.class); + // the violations are reported out of order - context.addViolation(new DummyRootNode().withCoords(15, 1, 15, 5)); - context.addViolation(new DummyRootNode().withCoords(1, 1, 2, 5)); + // line 2 + context.addViolation(node.newChild().withCoords(TextRegion.fromOffsetLength("the\n".length(), "code".length()))); + // line 1 + context.addViolation(node.newChild().withCoords(TextRegion.fromOffsetLength(0, "the".length()))); return null; }).when(rule).apply(any(Node.class), Mockito.any(RuleContext.class)); - TestDescriptor testDescriptor = new TestDescriptor("the code", "sample test", 2, rule, dummyLanguage); + TestDescriptor testDescriptor = new TestDescriptor(code, "sample test", 2, rule, dummyLanguage); testDescriptor.setReinitializeRule(false); - testDescriptor.setExpectedLineNumbers(Arrays.asList(1, 15)); + testDescriptor.setExpectedLineNumbers(Arrays.asList(1, 2)); ruleTester.runTest(testDescriptor); } diff --git a/pmd-xml/src/main/java/net/sourceforge/pmd/lang/xml/ast/internal/XmlNodeWrapper.java b/pmd-xml/src/main/java/net/sourceforge/pmd/lang/xml/ast/internal/XmlNodeWrapper.java index c620763d3f..306611f217 100644 --- a/pmd-xml/src/main/java/net/sourceforge/pmd/lang/xml/ast/internal/XmlNodeWrapper.java +++ b/pmd-xml/src/main/java/net/sourceforge/pmd/lang/xml/ast/internal/XmlNodeWrapper.java @@ -19,7 +19,6 @@ import org.w3c.dom.NodeList; import org.w3c.dom.Text; import net.sourceforge.pmd.internal.util.IteratorUtil; -import net.sourceforge.pmd.lang.document.FileLocation; import net.sourceforge.pmd.lang.document.TextDocument; import net.sourceforge.pmd.lang.document.TextRegion; import net.sourceforge.pmd.lang.rule.xpath.Attribute; @@ -58,10 +57,9 @@ class XmlNodeWrapper implements XmlNode { return parser.wrapDomNode(domNode); } - @Override - public FileLocation getReportLocation() { - return textDoc.toLocation(TextRegion.fromBothOffsets(startOffset, endOffset)); + public TextRegion getTextRegion() { + return TextRegion.fromBothOffsets(startOffset, endOffset); } @Override From b3818954ac3cbcac66256da46253c8927e75ddcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 24 Apr 2022 12:53:35 +0200 Subject: [PATCH 115/180] Doc --- .../pmd/cache/AbstractAnalysisCache.java | 4 +- .../pmd/lang/document/RootTextDocument.java | 25 ++--- .../pmd/lang/document/TextDocument.java | 99 +++++++++++++------ .../pmd/lang/document/TextRange2d.java | 12 +-- .../pmd/lang/DummyLanguageModule.java | 6 +- .../pmd/test/lang/DummyLanguageModule.java | 7 +- 6 files changed, 85 insertions(+), 68 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cache/AbstractAnalysisCache.java b/pmd-core/src/main/java/net/sourceforge/pmd/cache/AbstractAnalysisCache.java index ce0d43a13d..e640d44d58 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/cache/AbstractAnalysisCache.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/cache/AbstractAnalysisCache.java @@ -67,7 +67,7 @@ public abstract class AbstractAnalysisCache implements AnalysisCache { public boolean isUpToDate(final TextDocument document) { try (TimedOperation ignored = TimeTracker.startOperation(TimedOperationCategory.ANALYSIS_CACHE, "up-to-date check")) { // There is a new file being analyzed, prepare entry in updated cache - final AnalysisResult updatedResult = new AnalysisResult(document.getContent().getCheckSum(), new ArrayList<>()); + final AnalysisResult updatedResult = new AnalysisResult(document.getCheckSum(), new ArrayList<>()); updatedResultsCache.put(document.getPathId(), updatedResult); // Now check the old cache @@ -214,7 +214,7 @@ public abstract class AbstractAnalysisCache implements AnalysisCache { String fileName = file.getPathId(); AnalysisResult analysisResult = updatedResultsCache.get(fileName); if (analysisResult == null) { - analysisResult = new AnalysisResult(file.getContent().getCheckSum()); + analysisResult = new AnalysisResult(file.getCheckSum()); } final AnalysisResult nonNullAnalysisResult = analysisResult; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/RootTextDocument.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/RootTextDocument.java index 9e8ecbb3a3..dae3fed124 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/RootTextDocument.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/RootTextDocument.java @@ -62,6 +62,11 @@ final class RootTextDocument extends BaseCloseable implements TextDocument { backend.close(); } + @Override + public Chars getText() { + return content.getNormalizedText(); + } + @Override public FileLocation toLocation(TextRegion region) { checkInRange(region, this.getLength()); @@ -83,22 +88,6 @@ final class RootTextDocument extends BaseCloseable implements TextDocument { ); } - @Override - public int offsetAtLineColumn(int line, int column) { - SourceCodePositioner positioner = content.getPositioner(); - return positioner.offsetFromLineColumn(line, column); - } - - @Override - public boolean isInRange(TextPos2d textPos2d) { - if (textPos2d.getLine() <= content.getPositioner().getNumLines()) { - int maxColumn = content.getPositioner().offsetOfEndOfLine(textPos2d.getLine()); - return textPos2d.getColumn() - < content.getPositioner().columnFromOffset(textPos2d.getLine(), maxColumn); - } - return false; - } - @Override public TextPos2d lineColumnAtOffset(int offset, boolean inclusive) { long longPos = content.getPositioner().lineColFromOffset(offset, inclusive); @@ -130,8 +119,8 @@ final class RootTextDocument extends BaseCloseable implements TextDocument { } @Override - public TextFileContent getContent() { - return content; + public long getCheckSum() { + return content.getCheckSum(); } @Override diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextDocument.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextDocument.java index d1ded64a4f..6bb71432c8 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextDocument.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextDocument.java @@ -28,6 +28,47 @@ import net.sourceforge.pmd.util.datasource.DataSource; * from a text document. Exposing it here could lead to files being written * to from within rules, while we want to eventually build an API that allows * file edition based on AST manipulation. + * + *

Coordinates in TextDocument

+ * + * This interface is an abstraction over a piece of text, which might not + * correspond to the backing source file. This allows the document to + * be a view on a piece of a larger document (eg, a Javadoc comment, or + * a string in which a language is injected). Another use case is to perform + * escape translation, while preserving the line breaks of the original source. + * + *

This complicates addressing within a text document. To explain it, + * consider that there is always *one* text document that corresponds to + * the backing text file, which we call the root text document. + * Logical documents built on top of it are called views. + * + * Text documents use offsets and {@link TextRegion} to address their + * contents. These are always relative to the {@linkplain #getText() text} of + * the document. Line and column information are provided by {@link FileLocation} + * (see {@link #toLocation(TextRegion)}), and are always absolute (ie, + * represent actual source lines in the file). + * + *

For instance, say you have the following file (and root text document): + *

{@code
+ * l1
+ * l2 (* comment *)
+ * l3
+ * }
+ * and you create a view for just the section {@code (* comment *)}. + * Then, that view's offset 0 (start of the document) will map + * to the {@code (} character, while the root document's offset 0 maps + * to the start of {@code l1}. When calling {@code toLocation(caretAt(0))}, + * the view will however return {@code line 2, column 4}, ie, a line/column + * that can be found when inspecting the file. + * + *

To reduce the potential for mistakes, views do not provide access + * to their underlying text document. That way, nodes only have access + * to a single document, and their offsets can be assumed to be in the + * coordinate system of that document. + * + *

This interface does not provide a way to obtain line/column + * coordinates that are relative to a view's coordinate system. This + * would complicate the construction of views significantly. */ public interface TextDocument extends Closeable { // todo logical sub-documents, to support embedded languages @@ -80,9 +121,7 @@ public interface TextDocument extends Closeable { * * @see TextFileContent#getNormalizedText() */ - default Chars getText() { - return getContent().getNormalizedText(); - } + Chars getText(); /** * Returns a region of the {@linkplain #getText() text} as a character sequence. @@ -91,9 +130,11 @@ public interface TextDocument extends Closeable { /** - * Returns the current contents of the text file. See also {@link #getText()}. + * Returns a checksum for the contents of the file. + * + * @see TextFileContent#getCheckSum() */ - TextFileContent getContent(); + long getCheckSum(); /** * Returns a reader over the text of this document. @@ -135,37 +176,19 @@ public interface TextDocument extends Closeable { * the line/column information for both start and end offset of * the region. * - * @return A new file position + * @param region A region, in the coordinate system of this document + * + * @return A new file position, with absolute coordinates * * @throws IndexOutOfBoundsException If the argument is not a valid region in this document */ FileLocation toLocation(TextRegion region); - /** - * Returns the offset at the given line and column number. - * - * @param line Line number (1-based) - * @param column Column number (1-based) - * - * @return an offset (0-based) - */ - int offsetAtLineColumn(int line, int column); - - /** - * Returns true if the position is valid in this document. - */ - boolean isInRange(TextPos2d textPos2d); - - /** - * Returns the offset at the line and number. - */ - default int offsetAtLineColumn(TextPos2d pos2d) { - return offsetAtLineColumn(pos2d.getLine(), pos2d.getColumn()); - } - /** * Returns the line and column at the given offset (inclusive). + * Note that the line/column cannot be converted back. They are + * absolute in the coordinate system of the original document. * * @param offset A source offset (0-based), can range in {@code [0, length]}. * @@ -176,13 +199,15 @@ public interface TextDocument extends Closeable { } /** - * Returns the line and column at the given offset (inclusive). + * Returns the line and column at the given offset. * * @param offset A source offset (0-based), can range in {@code [0, length]}. * @param inclusive If the offset falls right after a line terminator, * two behaviours are possible. If the parameter is true, - * choose the position at the start of the next line. - * Otherwise choose the offset at the end of the line. + * choose the position at the start of the next line, + * otherwise choose the position at the end of the line. + * + * @return A position, in the coordinate system of the root document * * @throws IndexOutOfBoundsException if the offset is out of bounds */ @@ -203,7 +228,17 @@ public interface TextDocument extends Closeable { @Override void close() throws IOException; - + /** + * Create a new text document for the given text file. The document's + * coordinate system is the same as the original text file. + * + * @param textFile A text file + * + * @return A new text document + * + * @throws IOException If the file cannot be read ({@link TextFile#readContents()}) + * @throws NullPointerException If the parameter is null + */ static TextDocument create(TextFile textFile) throws IOException { return new RootTextDocument(textFile); } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextRange2d.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextRange2d.java index c60eb1a5c5..e1a2978a65 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextRange2d.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextRange2d.java @@ -17,20 +17,12 @@ public final class TextRange2d implements Comparable { private final int endCol; public TextRange2d(int startLine, int startCol, int endLine, int endCol) { - checkValid(startLine, startCol, endLine, endCol); this.startLine = startLine; this.startCol = startCol; this.endLine = endLine; this.endCol = endCol; - } - - private void checkValid(int startLine, int startCol, int endLine, int endCol) { - if (startCol < 1 || startLine < 1 || endLine < 1 || endCol < 1) { - throw new IllegalArgumentException( - "Not a valid range (l" + startLine + ", c" + startCol + ")-" - + "(l" + endLine + ", c" + endCol + ")" - ); - } + assert startCol >= 1 && startLine >= 1 && endLine >= 1 && endCol >= 1 + : "Not a valid range " + displayString(); } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/DummyLanguageModule.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/DummyLanguageModule.java index 67ea0b3513..b3cb7cefa2 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/DummyLanguageModule.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/DummyLanguageModule.java @@ -52,12 +52,12 @@ public class DummyLanguageModule extends BaseLanguageModule { } public static DummyRootNode parse(String code, String filename) { - TextDocument doc = TextDocument.readOnlyString(code, filename, DummyLanguageModule.getInstance().getDefaultVersion()); + LanguageVersion version = DummyLanguageModule.getInstance().getDefaultVersion(); ParserTask task = new ParserTask( - doc, + TextDocument.readOnlyString(code, filename, version), SemanticErrorReporter.noop() ); - return readLispNode(task); + return (DummyRootNode) version.getLanguageVersionHandler().getParser().parse(task); } diff --git a/pmd-test/src/main/java/net/sourceforge/pmd/test/lang/DummyLanguageModule.java b/pmd-test/src/main/java/net/sourceforge/pmd/test/lang/DummyLanguageModule.java index 27661c29e8..ab5c11f25c 100644 --- a/pmd-test/src/main/java/net/sourceforge/pmd/test/lang/DummyLanguageModule.java +++ b/pmd-test/src/main/java/net/sourceforge/pmd/test/lang/DummyLanguageModule.java @@ -7,6 +7,7 @@ package net.sourceforge.pmd.test.lang; import net.sourceforge.pmd.lang.AbstractPmdLanguageVersionHandler; import net.sourceforge.pmd.lang.BaseLanguageModule; import net.sourceforge.pmd.lang.LanguageRegistry; +import net.sourceforge.pmd.lang.LanguageVersion; import net.sourceforge.pmd.lang.ast.AstInfo; import net.sourceforge.pmd.lang.ast.Parser; import net.sourceforge.pmd.lang.ast.Parser.ParserTask; @@ -43,12 +44,12 @@ public class DummyLanguageModule extends BaseLanguageModule { } public static DummyRootNode parse(String code, String filename) { - TextDocument doc = TextDocument.readOnlyString(code, filename, DummyLanguageModule.getInstance().getDefaultVersion()); + LanguageVersion version = DummyLanguageModule.getInstance().getDefaultVersion(); ParserTask task = new ParserTask( - doc, + TextDocument.readOnlyString(code, filename, version), SemanticErrorReporter.noop() ); - return (DummyRootNode) doc.getLanguageVersion().getLanguageVersionHandler().getParser().parse(task); + return (DummyRootNode) version.getLanguageVersionHandler().getParser().parse(task); } public static class Handler extends AbstractPmdLanguageVersionHandler { From 0d10425aac5a989482d30f267f4505adab66b2c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 24 Apr 2022 14:56:58 +0200 Subject: [PATCH 116/180] Pull some trimming logic into pmd-core --- .../sourceforge/pmd/cpd/SimpleRenderer.java | 7 +- .../sourceforge/pmd/lang/document/Chars.java | 48 ++++++ .../net/sourceforge/pmd/util/StringUtil.java | 146 ++++++++++++------ .../pmd/lang/java/ast/ASTStringLiteral.java | 99 ++++-------- .../pmd/testframework/RuleTst.java | 10 +- 5 files changed, 188 insertions(+), 122 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/SimpleRenderer.java b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/SimpleRenderer.java index 9d499def1a..79e8cea468 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/SimpleRenderer.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/SimpleRenderer.java @@ -49,12 +49,7 @@ public class SimpleRenderer implements Renderer, CPDRenderer { String source = match.getSourceCodeSlice(); if (trimLeadingWhitespace) { - String[] lines = source.split("\n"); - int trimDepth = StringUtil.maxCommonLeadingWhitespaceForAll(lines); - if (trimDepth > 0) { - lines = StringUtil.trimStartOn(lines, trimDepth); - } - for (String line : lines) { + for (String line : StringUtil.linesWithTrimIndent(source)) { writer.append(line).append(PMD.EOL); } return; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java index 664a58330c..963ed282e4 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java @@ -13,6 +13,8 @@ import java.nio.CharBuffer; import java.nio.charset.Charset; import java.util.Iterator; import java.util.regex.Pattern; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; import org.checkerframework.checker.nullness.qual.NonNull; @@ -196,6 +198,27 @@ public final class Chars implements CharSequence { return -1; } + /** + * See {@link String#lastIndexOf(int, int)}. + */ + public int lastIndexOf(int ch, int fromIndex) { + if (fromIndex < 0 || fromIndex >= len) { + return -1; + } + // we want to avoid searching too far in the string + // so we don't use String#indexOf, as it would be looking + // in the rest of the file too, which in the worst case is + // horrible + + for (int i = start + fromIndex; i >= start; i--) { + char c = str.charAt(i); + if (c == ch) { + return i - start; + } + } + return -1; + } + /** * See {@link String#startsWith(String, int)}. */ @@ -221,6 +244,13 @@ public final class Chars implements CharSequence { return str.charAt(start + fromIndex) == prefix; } + /** + * See {@link String#endsWith(String)}. + */ + public boolean endsWith(String suffix) { + return startsWith(suffix, length() - suffix.length()); + } + /** * Returns a subsequence which does not start with control characters ({@code <= 32}). * This is consistent with {@link String#trim()}. @@ -254,6 +284,17 @@ public final class Chars implements CharSequence { return trimStart().trimEnd(); } + /** + * Remove the suffix if it is present, otherwise returns this. + */ + public Chars removeSuffix(String charSeq) { + int trimmedLen = length() - charSeq.length(); + if (startsWith(charSeq, trimmedLen)) { + return slice(0, trimmedLen); + } + return this; + } + /** * Returns true if this char sequence is logically equal to the @@ -443,6 +484,13 @@ public final class Chars implements CharSequence { }; } + /** + * Returns a stream of lines yielded by {@link #lines()}. + */ + public Stream lineStream() { + return StreamSupport.stream(lines().spliterator(), false); + } + /** * Returns a new reader for the whole contents of this char sequence. diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/StringUtil.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/StringUtil.java index 79cd5da71f..4c82ffe662 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/StringUtil.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/StringUtil.java @@ -5,6 +5,7 @@ package net.sourceforge.pmd.util; import java.text.MessageFormat; +import java.util.Arrays; import java.util.List; import java.util.Locale; import java.util.regex.Matcher; @@ -15,6 +16,7 @@ import org.apache.commons.lang3.StringUtils; import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.internal.util.AssertionUtil; +import net.sourceforge.pmd.lang.document.Chars; /** * A number of String-specific utility methods for use by PMD or its IDE @@ -278,53 +280,21 @@ public final class StringUtil { * * @throws NullPointerException If the parameter is null */ - public static int maxCommonLeadingWhitespaceForAll(String[] strings) { - - int shortest = lengthOfShortestIn(strings); - if (shortest == 0) { - return 0; - } - - char[] matches = new char[shortest]; - - for (int m = 0; m < matches.length; m++) { - matches[m] = strings[0].charAt(m); - if (!Character.isWhitespace(matches[m])) { - return m; - } - for (String str : strings) { - if (str.charAt(m) != matches[m]) { - return m; - } + private static int maxCommonLeadingWhitespaceForAll(List lines) { + // the max *common* leading WS length is the min length of all leading WS + int maxCommonWs = Integer.MAX_VALUE; + for (int i = 0; i < lines.size(); i++) { + CharSequence line = lines.get(i); + // compute common prefix + if (!StringUtils.isAllBlank(line) || i == lines.size() - 1) { + maxCommonWs = Math.min(maxCommonWs, StringUtil.countLeadingWhitespace(line)); } } - - return shortest; - } - - - /** - * Return the length of the shortest string in the array. If the collection - * is empty or any one of them is null then it returns 0. - * - * @throws NullPointerException If the parameter is null - */ - public static int lengthOfShortestIn(String[] strings) { - - if (strings.length == 0) { - return 0; + if (maxCommonWs == Integer.MAX_VALUE) { + // common prefix not found + maxCommonWs = 0; } - - int minLength = Integer.MAX_VALUE; - - for (String string : strings) { - if (string == null) { - return 0; - } - minLength = Math.min(minLength, string.length()); - } - - return minLength; + return maxCommonWs; } @@ -334,7 +304,7 @@ public final class StringUtil { * * @return String[] */ - public static String[] trimStartOn(String[] strings, int trimDepth) { + private static String[] trimStartOn(String[] strings, int trimDepth) { if (trimDepth == 0) { return strings; @@ -347,6 +317,92 @@ public final class StringUtil { return results; } + /** + * Trim common indentation in the lines of the string. + * Does not discard + */ + public static StringBuilder trimIndent(Chars string) { + List lines = string.lineStream().collect(Collectors.toList()); + StringBuilder sb = new StringBuilder(string.length()); + trimIndentIntoStringBuilder(lines, sb); + return sb; + } + + public static void trimIndentIntoStringBuilder(List lines, StringBuilder sb) { + int prefixLength = maxCommonLeadingWhitespaceForAll(lines); + appendWithoutCommonPrefix(lines, prefixLength, sb); + } + + private static void appendWithoutCommonPrefix(List lines, int prefixLength, StringBuilder output) { + for (int i = 0; i < lines.size(); i++) { + Chars line = lines.get(i); + // remove common whitespace prefix + if (!StringUtils.isAllBlank(line) && line.length() >= prefixLength) { + line = line.subSequence(prefixLength, line.length()); + } + line = line.trimEnd(); + line.appendChars(output); + + boolean isLastLine = i == lines.size() - 1; + boolean isFirstLine = i == 0; + // todo is this &&? + if (!isLastLine || !isFirstLine && !StringUtils.isAllBlank(line)) { + output.append('\n'); // normalize line endings to LF + } + } + } + + /** + * Remove trailing and leading blank lines. + */ + public static Chars trimBlankLines(Chars string) { + int offsetOfFirstNonBlankChar = string.length(); + for (int i = 0; i < string.length(); i++) { + if (!Character.isWhitespace(string.charAt(i))) { + offsetOfFirstNonBlankChar = i; + break; + } + } + int offsetOfLastNonBlankChar = 0; + for (int i = string.length() - 1; i > offsetOfFirstNonBlankChar; i--) { + if (!Character.isWhitespace(string.charAt(i))) { + offsetOfLastNonBlankChar = i; + break; + } + } + + int lastNonBlankLine = string.indexOf('\n', offsetOfLastNonBlankChar); + int firstNonBlankLine = string.lastIndexOf('\n', offsetOfFirstNonBlankChar); + + return string.subSequence( + minus1Default(firstNonBlankLine, 0), + minus1Default(lastNonBlankLine, string.length()) + ); + } + + private static int minus1Default(int i, int defaultValue) { + return i == -1 ? defaultValue : i; + } + + + private static int countLeadingWhitespace(CharSequence s) { + int count = 0; + while (count < s.length() && Character.isWhitespace(s.charAt(count))) { + count++; + } + return count; + } + + public static String[] linesWithTrimIndent(String source) { + String[] lines = source.split("\n"); + int trimDepth = maxCommonLeadingWhitespaceForAll(Arrays.asList(lines)); + if (trimDepth > 0) { + lines = trimStartOn(lines, trimDepth); + } + return lines; + } + + /** * Are the two String values the same. The Strings can be optionally trimmed diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStringLiteral.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStringLiteral.java index 124d972f9b..eb6cf5c377 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStringLiteral.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStringLiteral.java @@ -4,14 +4,16 @@ package net.sourceforge.pmd.lang.java.ast; -import java.util.Arrays; import java.util.List; +import java.util.stream.Collectors; import org.apache.commons.lang3.StringEscapeUtils; -import org.apache.commons.lang3.StringUtils; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; +import net.sourceforge.pmd.lang.document.Chars; +import net.sourceforge.pmd.util.StringUtil; + /** * Represents a string literal. The image of this node is the literal as it appeared * in the source ({@link #getText()}). {@link #getConstValue()} allows to recover @@ -71,7 +73,7 @@ public final class ASTStringLiteral extends AbstractLiteral implements ASTLitera @Override protected @Nullable Object buildConstValue() { if (isTextBlock()) { - return determineTextBlockContent(getImage()); + return determineTextBlockContent(getText()); } else { CharSequence image = getText(); CharSequence woDelims = image.subSequence(1, image.length() - 1); @@ -79,46 +81,36 @@ public final class ASTStringLiteral extends AbstractLiteral implements ASTLitera } } - static String determineTextBlockContent(String image) { - // normalize line endings to LF - 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")); - 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'); - } - } - + static String determineTextBlockContent(Chars image) { + List lines = getContentLines(image); + StringBuilder sb = new StringBuilder(image.length()); + StringUtil.trimIndentIntoStringBuilder(lines, sb); interpretEscapeSequences(sb); return sb.toString(); } + static String determineTextBlockContent(String image) { + return determineTextBlockContent(Chars.wrap(image)); + } + + /** + * Returns the lines of the parameter minus the delimiters. + */ + private static @NonNull List getContentLines(Chars chars) { + List lines = chars.lineStream().collect(Collectors.toList()); + assert lines.size() >= 2 : "invalid text block syntax " + chars; + // remove first line, it's just """ and some whitespace + lines = lines.subList(1, lines.size()); + + // trim the """ off the last line. + int lastIndex = lines.size() - 1; + Chars lastLine = lines.get(lastIndex); + assert lastLine.endsWith(TEXTBLOCK_DELIMITER); + lines.set(lastIndex, lastLine.removeSuffix(TEXTBLOCK_DELIMITER)); + + return lines; + } + 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 @@ -172,33 +164,4 @@ public final class ASTStringLiteral extends AbstractLiteral implements ASTLitera } } } - - private static int determineContentStart(String s) { - int start = TEXTBLOCK_DELIMITER.length(); // this is the opening delimiter - // 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) == '\n') { - return start + 1; - } - 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-test/src/main/java/net/sourceforge/pmd/testframework/RuleTst.java b/pmd-test/src/main/java/net/sourceforge/pmd/testframework/RuleTst.java index 5f1bd5bfa3..ff358b038b 100644 --- a/pmd-test/src/main/java/net/sourceforge/pmd/testframework/RuleTst.java +++ b/pmd-test/src/main/java/net/sourceforge/pmd/testframework/RuleTst.java @@ -44,16 +44,19 @@ import net.sourceforge.pmd.RuleViolation; import net.sourceforge.pmd.lang.Language; import net.sourceforge.pmd.lang.LanguageRegistry; import net.sourceforge.pmd.lang.LanguageVersion; +import net.sourceforge.pmd.lang.document.Chars; import net.sourceforge.pmd.lang.document.TextFile; import net.sourceforge.pmd.processor.AbstractPMDProcessor; import net.sourceforge.pmd.properties.PropertyDescriptor; import net.sourceforge.pmd.renderers.TextRenderer; import net.sourceforge.pmd.reporting.GlobalAnalysisListener; +import net.sourceforge.pmd.util.StringUtil; /** * Advanced methods for test cases */ public abstract class RuleTst { + private final DocumentBuilder documentBuilder; /** Use a single classloader for all tests. */ @@ -483,15 +486,16 @@ public abstract class RuleTst { throw new RuntimeException("No matching code fragment found for coderef"); } } + code = StringUtil.trimBlankLines(Chars.wrap(code)).toString(); String description = getNodeValue(testCode, "description", true); - int expectedProblems = Integer.parseInt(getNodeValue(testCode, "expected-problems", true)); + int expectedProblems = Integer.parseInt(getNodeValue(testCode, "expected-problems", true).trim()); String languageVersionString = getNodeValue(testCode, "source-type", false); if (languageVersionString == null) { tests[i] = new TestDescriptor(code, description, expectedProblems, rule); } else { - + languageVersionString = languageVersionString.trim(); LanguageVersion languageVersion = parseSourceType(languageVersionString); if (languageVersion != null) { tests[i] = new TestDescriptor(code, description, expectedProblems, rule, languageVersion); @@ -553,6 +557,6 @@ public abstract class RuleTst { buffer.append(node.getNodeValue()); } } - return buffer.toString().trim(); + return buffer.toString(); } } From 3f9fb52a9bb70383ba1f542022bb2096679efb03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 24 Apr 2022 15:39:22 +0200 Subject: [PATCH 117/180] Treat \r as line separator as well --- .../sourceforge/pmd/lang/document/Chars.java | 33 +++++---- .../pmd/lang/document/TextFileContent.java | 72 ++++++++++++------- .../pmd/lang/document/CharsTest.java | 7 ++ .../lang/document/TextFileContentTest.java | 25 ++++--- 4 files changed, 92 insertions(+), 45 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java index 963ed282e4..f9d4b91c1e 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java @@ -5,6 +5,7 @@ package net.sourceforge.pmd.lang.document; +import java.io.BufferedReader; import java.io.IOException; import java.io.Reader; import java.io.Writer; @@ -452,8 +453,8 @@ public final class Chars implements CharSequence { /** * Returns an iterable over the lines of this char sequence. The lines - * are yielded without line separators. For the purposes of this method, - * a line delimiter is {@code LF} or {@code CR+LF}. + * are yielded without line separators. Like {@link BufferedReader#readLine()}, + * a line delimiter is {@code CR}, {@code LF} or {@code CR+LF}. */ public Iterable lines() { return () -> new Iterator() { @@ -467,19 +468,27 @@ public final class Chars implements CharSequence { @Override public Chars next() { - int nl = indexOf('\n', pos); - Chars next; - if (nl < 0) { - next = subSequence(pos, max); + int curPos = pos; + int cr = indexOf('\r', curPos); + int lf = indexOf('\n', curPos); + + if (cr != -1 && lf != -1) { + // found both CR and LF + int min = Math.min(cr, lf); + pos = lf == cr + 1 ? lf + 1 // CRLF + : min + 1; + + return subSequence(curPos, min); + } else if (cr == -1 && lf == -1) { + // no following line terminator, cut until the end pos = max; - return next; - } else if (startsWith('\r', nl - 1)) { - next = subSequence(pos, nl - 1); + return subSequence(curPos, max); } else { - next = subSequence(pos, nl); + // lf or cr (exactly one is != -1 and max returns that one) + int idx = Math.max(cr, lf); + pos = idx + 1; + return subSequence(curPos, idx); } - pos = nl + 1; - return next; } }; } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextFileContent.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextFileContent.java index 84b3a86c2f..0d4234c5ae 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextFileContent.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextFileContent.java @@ -41,7 +41,7 @@ public final class TextFileContent { private static final int DEFAULT_BUFSIZE = 8192; - private static final Pattern NEWLINE_PATTERN = Pattern.compile("\r\n|\n"); + private static final Pattern NEWLINE_PATTERN = Pattern.compile("\r\n?|\n"); private static final String FALLBACK_LINESEP = System.lineSeparator(); private final Chars cdata; @@ -61,9 +61,10 @@ public final class TextFileContent { * The text of the file, with the following normalizations: *

    *
  • Line endings are normalized to {@value NORMALIZED_LINE_TERM}. - * For this purpose, a line ending is either {@code \r\n} or {@code \n} - * (CRLF or LF), not the full range of unicode line endings. This is - * consistent with {@link BufferedReader#readLine()} for example. + * For this purpose, a line ending is either {@code \r}, {@code \r\n} + * or {@code \n} (CR, CRLF or LF), not the full range of unicode line + * endings. This is consistent with {@link BufferedReader#readLine()}, + * and the JLS, for example. *
  • An initial byte-order mark is removed, if any. *
*/ @@ -207,35 +208,52 @@ public final class TextFileContent { } while (n != IOUtils.EOF) { - if (updateChecksum) { // if we use a checked input stream we dont need to update the checksum manually + if (updateChecksum) { + // if we use a checked input stream we dont need to update the checksum manually + // note that this checksum operates on non-normalized characters updateChecksum(checksum, CharBuffer.wrap(cbuf, nextCharToCopy, n)); } + int offsetDiff = 0; + for (int i = nextCharToCopy; i < n; i++) { char c = cbuf[i]; - if (afterCr && c != NORMALIZED_LINE_TERM_CHAR && i == 0) { - // we saw a \r at the end of the last buffer, but didn't copy it - // it's actually not followed by an \n - result.append('\r'); - } - - if (c == NORMALIZED_LINE_TERM_CHAR) { + if (afterCr || c == NORMALIZED_LINE_TERM_CHAR) { final String newLineTerm; - if (afterCr) { - newLineTerm = "\r\n"; - + final int newLineOffset; + if (afterCr && c != NORMALIZED_LINE_TERM_CHAR) { + // we saw a \r last iteration, but didn't copy it + // it's not followed by an \n + newLineTerm = "\r"; + newLineOffset = bufOffset + i + offsetDiff; if (i > 0) { cbuf[i - 1] = '\n'; // replace the \r with a \n - // copy up to and including the \r, which was replaced - result.append(cbuf, nextCharToCopy, i - nextCharToCopy); - nextCharToCopy = i + 1; // set the next char to copy to after the \n + } else { + // The CR was trailing a buffer, so it's not in the current buffer and wasn't copied. + // Append a newline. + result.append(NORMALIZED_LINE_TERM); } } else { - // just \n - newLineTerm = NORMALIZED_LINE_TERM; + if (afterCr) { + newLineTerm = "\r\n"; + + if (i > 0) { + cbuf[i - 1] = '\n'; // replace the \r with a \n + // copy up to and including the \r, which was replaced + result.append(cbuf, nextCharToCopy, i - nextCharToCopy); + nextCharToCopy = i + 1; // set the next char to copy to after the \n + } + // Since we're replacing a 2-char delimiter with a single char, + // the offset of the line needs to be adjusted. + offsetDiff--; + } else { + // just \n + newLineTerm = "\n"; + } + newLineOffset = bufOffset + i + offsetDiff + 1; } - positionerBuilder.addLineEndAtOffset(bufOffset + i + 1); + positionerBuilder.addLineEndAtOffset(newLineOffset); detectedLineTerm = detectLineTerm(detectedLineTerm, newLineTerm, fallbackLineSep); } afterCr = c == '\r'; @@ -250,18 +268,21 @@ public final class TextFileContent { } nextCharToCopy = 0; - bufOffset += n; + bufOffset += n + offsetDiff; n = input.read(cbuf); } // end while + if (afterCr) { // we're at EOF, so it's not followed by \n + result.append(NORMALIZED_LINE_TERM); + positionerBuilder.addLineEndAtOffset(bufOffset); + detectedLineTerm = detectLineTerm(detectedLineTerm, "\r", fallbackLineSep); + } + if (detectedLineTerm == null) { // no line terminator in text detectedLineTerm = fallbackLineSep; } - if (afterCr) { // we're at EOF, so it's not followed by \n - result.append('\r'); - } return new TextFileContent(Chars.wrap(result), detectedLineTerm, checksum.getValue(), positionerBuilder.build(bufOffset)); } @@ -272,6 +293,7 @@ public final class TextFileContent { if (curLineTerm.equals(newLineTerm)) { return curLineTerm; } else { + // todo maybe we should report a warning return fallback; // mixed line terminators, fallback to system default } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/CharsTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/CharsTest.java index e872f0e288..2e14ffd634 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/CharsTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/CharsTest.java @@ -199,6 +199,13 @@ public class CharsTest { assertEquals(listOf("aa"), lines); } + @Test + public void linesTest3WithCr() { + Chars bc = Chars.wrap("aa\rb"); + List lines = CollectionUtil.map(bc.lines(), Chars::toString); + assertEquals(listOf("aa", "b"), lines); + } + @Test public void testEqualsHashCode() { diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextFileContentTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextFileContentTest.java index f21d400b43..05dd38fed9 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextFileContentTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextFileContentTest.java @@ -34,7 +34,7 @@ public class TextFileContentTest { @Parameters(source = TextContentOrigin.class) public void testMixedDelimiters(TextContentOrigin origin) throws IOException { TextFileContent content = origin.normalize("a\r\nb\n\rc"); - Assert.assertEquals(Chars.wrap("a\nb\n\rc"), content.getNormalizedText()); + Assert.assertEquals(Chars.wrap("a\nb\n\nc"), content.getNormalizedText()); Assert.assertEquals(LINESEP_SENTINEL, content.getLineTerminator()); } @@ -85,6 +85,7 @@ public class TextFileContentTest { public void testCrlfSplitOnBuffer() throws IOException { StringReader reader = new StringReader("a\r\nb"); // now the buffer is of size 2, so we read first [a\r] then [\nb] + // but there is a single line TextFileContent content = TextFileContent.normalizingRead(reader, 2, System.lineSeparator()); Assert.assertEquals(Chars.wrap("a\nb"), content.getNormalizedText()); Assert.assertEquals("\r\n", content.getLineTerminator()); @@ -94,18 +95,26 @@ public class TextFileContentTest { public void testCrSplitOnBufferFp() throws IOException { StringReader reader = new StringReader("a\rb\n"); // the buffer is of size 2, so we read first [a\r] then [b\n] - // the \r is not a line terminator though + // the \r is a line terminator on its own TextFileContent content = TextFileContent.normalizingRead(reader, 2, LINESEP_SENTINEL); - Assert.assertEquals(Chars.wrap("a\rb\n"), content.getNormalizedText()); - Assert.assertEquals("\n", content.getLineTerminator()); + Assert.assertEquals(Chars.wrap("a\nb\n"), content.getNormalizedText()); + Assert.assertEquals(LINESEP_SENTINEL, content.getLineTerminator()); } @Test @Parameters(source = TextContentOrigin.class) public void testCrCr(TextContentOrigin origin) throws IOException { TextFileContent content = origin.normalize("a\r\rb"); - Assert.assertEquals(Chars.wrap("a\r\rb"), content.getNormalizedText()); - Assert.assertEquals(LINESEP_SENTINEL, content.getLineTerminator()); + Assert.assertEquals(Chars.wrap("a\n\nb"), content.getNormalizedText()); + Assert.assertEquals("\r", content.getLineTerminator()); + } + + @Test + @Parameters(source = TextContentOrigin.class) + public void testCrIsEol(TextContentOrigin origin) throws IOException { + TextFileContent content = origin.normalize("a\rb\rdede"); + Assert.assertEquals(Chars.wrap("a\nb\ndede"), content.getNormalizedText()); + Assert.assertEquals("\r", content.getLineTerminator()); } @Test @@ -122,8 +131,8 @@ public class TextFileContentTest { // the buffer is of size 2, so we read first [a\r] then [\ro] // the \r is not a line terminator though TextFileContent content = TextFileContent.normalizingRead(reader, 2, LINESEP_SENTINEL); - Assert.assertEquals(Chars.wrap("a\r\r"), content.getNormalizedText()); - Assert.assertEquals(LINESEP_SENTINEL, content.getLineTerminator()); + Assert.assertEquals(Chars.wrap("a\n\n"), content.getNormalizedText()); + Assert.assertEquals("\r", content.getLineTerminator()); } enum TextContentOrigin { From 32c8581f0478fade7d6017c0c15bc8f62e76b17c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 24 Apr 2022 15:56:35 +0200 Subject: [PATCH 118/180] Add missing tests --- .../lang/document/SourceCodePositioner.java | 11 ++- .../pmd/lang/document/CharsTest.java | 41 +++++++++ .../pmd/lang/document/TextDocumentTest.java | 85 +++++++++++++++---- 3 files changed, 118 insertions(+), 19 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/SourceCodePositioner.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/SourceCodePositioner.java index 56ef19e26f..ed4301b827 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/SourceCodePositioner.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/SourceCodePositioner.java @@ -44,7 +44,7 @@ final class SourceCodePositioner { int lineIdx = line - 1; // zero-based - if (offset == lineOffsets[lineIdx] && !inclusive) { + if (lineIdx != 0 && offset == lineOffsets[lineIdx] && !inclusive) { // we're precisely on the start of a line // if inclusive, prefer the position at the end of the previous line // This is a subtlety that the other methods for offset -> line do not @@ -157,7 +157,8 @@ final class SourceCodePositioner { */ public int offsetOfEndOfLine(final int line) { if (!isValidLine(line)) { - throw new IndexOutOfBoundsException(line + " is not a valid line number, expected at most " + lineOffsets.length); + throw new IndexOutOfBoundsException( + line + " is not a valid line number, expected at most " + lineOffsets.length); } return lineOffsets[line]; @@ -187,7 +188,11 @@ final class SourceCodePositioner { } private int getLastColumnOfLine(int line) { - return 1 + lineOffsets[line] - lineOffsets[line - 1]; + if (line == 0) { + return 1 + lineOffsets[line]; + } else { + return 1 + lineOffsets[line] - lineOffsets[line - 1]; + } } /** diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/CharsTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/CharsTest.java index 2e14ffd634..7b193fcb29 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/CharsTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/CharsTest.java @@ -16,6 +16,7 @@ import static org.junit.Assert.assertTrue; import java.io.IOException; import java.io.StringWriter; import java.util.List; +import java.util.stream.Collectors; import org.junit.Test; @@ -125,6 +126,23 @@ public class CharsTest { assertEquals(2, bc.indexOf("bx", 0)); } + @Test + public void lastIndexOf() { + Chars bc = Chars.wrap("aaaaabcdb").slice(5, 2); + // -- + assertEquals(0, bc.lastIndexOf('b', 0)); + assertEquals(0, bc.lastIndexOf('b', 1)); + assertEquals(1, bc.lastIndexOf('c', 1)); + assertEquals(-1, bc.lastIndexOf('c', 0)); + + assertEquals(-1, bc.lastIndexOf('d', 0)); + + assertEquals(-1, bc.lastIndexOf('x', 0)); + assertEquals(-1, bc.lastIndexOf('a', -1)); + assertEquals(-1, bc.lastIndexOf('a', 0)); + assertEquals(-1, bc.lastIndexOf('a', 1)); + } + @Test public void startsWith() { Chars bc = Chars.wrap("abcdb").slice(1, 2); @@ -151,6 +169,22 @@ public class CharsTest { } + @Test + public void removeSuffix() { + Chars bc = Chars.wrap("abcdb").slice(1, 2); + // -- + + assertEquals("bc", bc.toString()); + assertEquals("b", bc.removeSuffix("c").toString()); + assertEquals("", bc.removeSuffix("bc").toString()); + + bc = Chars.wrap("aaaaaaa").slice(2, 3); + // --- + + assertEquals("", bc.removeSuffix("aaa").toString()); + assertEquals("aaa", bc.removeSuffix("aaaa").toString()); + } + @Test public void trimNoop() { Chars bc = Chars.wrap("abcdb").slice(1, 2); @@ -199,6 +233,13 @@ public class CharsTest { assertEquals(listOf("aa"), lines); } + @Test + public void linesStreamTest() { + Chars bc = Chars.wrap("aa\nb\rded\r\nlff"); + List lines = bc.lineStream().map(Chars::toString).collect(Collectors.toList()); + assertEquals(listOf("aa", "b", "ded", "lff"), lines); + } + @Test public void linesTest3WithCr() { Chars bc = Chars.wrap("aa\rb"); diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextDocumentTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextDocumentTest.java index 22620da346..b5e98928e5 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextDocumentTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextDocumentTest.java @@ -4,16 +4,26 @@ package net.sourceforge.pmd.lang.document; +import static net.sourceforge.pmd.lang.document.TextPos2d.pos2d; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThrows; +import java.io.IOException; + +import org.apache.commons.io.IOUtils; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import net.sourceforge.pmd.lang.DummyLanguageModule; import net.sourceforge.pmd.lang.LanguageRegistry; import net.sourceforge.pmd.lang.LanguageVersion; +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; + +@RunWith(JUnitParamsRunner.class) public class TextDocumentTest { @Rule @@ -32,13 +42,10 @@ public class TextDocumentTest { FileLocation withLines = doc.toLocation(region); - // todo rename to getStartLine assertEquals(1, withLines.getStartLine()); assertEquals(1, withLines.getEndLine()); - // todo rename to getStartLine assertEquals(1, withLines.getStartColumn()); assertEquals(1 + "bonjour".length(), withLines.getEndColumn()); - // todo rename to getStartLine assertEquals("bonjour".length(), withLines.getEndColumn() - withLines.getStartColumn()); } @@ -50,13 +57,10 @@ public class TextDocumentTest { assertEquals("bonjour\n", doc.sliceText(region).toString()); FileLocation withLines = doc.toLocation(region); - // todo rename to getStartLine assertEquals(1, withLines.getStartLine()); assertEquals(1, withLines.getEndLine()); - // todo rename to getStartLine assertEquals(1, withLines.getStartColumn()); assertEquals(1 + "bonjour\n".length(), withLines.getEndColumn()); - // todo rename to getStartLine assertEquals("bonjour\n".length(), withLines.getEndColumn() - withLines.getStartColumn()); } @@ -71,10 +75,8 @@ public class TextDocumentTest { FileLocation withLines = doc.toLocation(region); - // todo rename to getStartLine assertEquals(2, withLines.getStartLine()); assertEquals(2, withLines.getEndLine()); - // todo rename to getStartLine assertEquals(1, withLines.getStartColumn()); assertEquals(1, withLines.getEndColumn()); } @@ -91,10 +93,8 @@ public class TextDocumentTest { FileLocation withLines = doc.toLocation(region); - // todo rename to getStartLine assertEquals(1, withLines.getStartLine()); assertEquals(1, withLines.getEndLine()); - // todo rename to getStartLine assertEquals(1 + "bonjour".length(), withLines.getStartColumn()); assertEquals(1 + "bonjour\n".length(), withLines.getEndColumn()); } @@ -108,10 +108,8 @@ public class TextDocumentTest { FileLocation withLines = doc.toLocation(region); - // todo rename to getStartLine assertEquals(1, withLines.getStartLine()); assertEquals(1, withLines.getEndLine()); - // todo rename to getStartLine assertEquals(1, withLines.getStartColumn()); assertEquals(1 + doc.getLength(), withLines.getEndColumn()); } @@ -128,14 +126,36 @@ public class TextDocumentTest { FileLocation withLines = doc.toLocation(region); - // todo rename to getStartLine assertEquals(1, withLines.getStartLine()); assertEquals(3, withLines.getEndLine()); - // todo rename to getStartLine assertEquals(1 + "bonjou".length(), withLines.getStartColumn()); assertEquals(1 + "tri".length(), withLines.getEndColumn()); } + + @Test + public void testLineColumnFromOffset() { + TextDocument doc = TextDocument.readOnlyString("ab\ncd\n", dummyVersion); + + assertPos2dEqualsAt(doc, 0, "a", pos2d(1, 1), true); + assertPos2dEqualsAt(doc, 0, "a", pos2d(1, 1), false); + assertPos2dEqualsAt(doc, 1, "b", pos2d(1, 2), true); + assertPos2dEqualsAt(doc, 2, "\n", pos2d(1, 3), true); + assertPos2dEqualsAt(doc, 3, "c", pos2d(2, 1), true); + assertPos2dEqualsAt(doc, 3, "c", pos2d(1, 4), false); + assertPos2dEqualsAt(doc, 4, "d", pos2d(2, 2), true); + assertPos2dEqualsAt(doc, 5, "\n", pos2d(2, 3), true); + // EOF caret position + assertEquals(pos2d(3, 1), doc.lineColumnAtOffset(6)); + assertThrows(IndexOutOfBoundsException.class, () -> doc.lineColumnAtOffset(7)); + } + + private void assertPos2dEqualsAt(TextDocument doc, int offset, String c, TextPos2d pos, boolean inclusive) { + Chars slicedChar = doc.sliceText(TextRegion.fromOffsetLength(offset, 1)); + assertEquals(c, slicedChar.toString()); + assertEquals(pos, doc.lineColumnAtOffset(offset, inclusive)); + } + @Test public void testEmptyRegion() { TextDocument doc = TextDocument.readOnlyString("bonjour\noha\ntristesse", dummyVersion); @@ -148,10 +168,8 @@ public class TextDocumentTest { FileLocation withLines = doc.toLocation(region); - // todo rename to getStartLine assertEquals(1, withLines.getStartLine()); assertEquals(1, withLines.getEndLine()); - // todo rename to getStartLine assertEquals(1 + "bonjour".length(), withLines.getStartColumn()); assertEquals(1 + "bonjour".length(), withLines.getEndColumn()); } @@ -170,6 +188,25 @@ public class TextDocumentTest { assertThrows(IndexOutOfBoundsException.class, () -> doc.createLineRange(0, 2)); } + @Test + @Parameters(source = DocumentsProvider.class) + public void testEntireRegion(TextDocument doc) { + assertEquals("getEntireRegion should return something based on length", + TextRegion.fromOffsetLength(0, doc.getLength()), + doc.getEntireRegion()); + } + + @Test + @Parameters(source = DocumentsProvider.class) + public void testReader(TextDocument doc) throws IOException { + + assertEquals("NewReader should read the text", + doc.getText().toString(), + IOUtils.toString(doc.newReader()) + ); + + } + @Test public void testRegionOutOfBounds() { TextDocument doc = TextDocument.readOnlyString("bonjour\noha\ntristesse", dummyVersion); @@ -179,4 +216,20 @@ public class TextDocumentTest { TextRegion.isValidRegion(0, 40, doc); } + // for junit params runner + public static final class DocumentsProvider { + + + @SuppressWarnings("resource") + public static Object[] provideParameters() { + LanguageVersion dummyVersion = DummyLanguageModule.getInstance().getDefaultVersion(); + return new TextDocument[] { + TextDocument.readOnlyString("bonjour\noha\ntristesse", dummyVersion), + TextDocument.readOnlyString("bonjour\n", dummyVersion), + TextDocument.readOnlyString("\n", dummyVersion), + TextDocument.readOnlyString("", dummyVersion), + }; + } + } + } From 2d2a1c5531905f609f1ee15beb4e05e3197e0a7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 24 Apr 2022 16:33:00 +0200 Subject: [PATCH 119/180] More tests --- .../pmd/lang/document/TextRange2d.java | 11 ++--- .../pmd/lang/document/TextRegion.java | 8 ++-- .../pmd/lang/document/FileLocationTest.java | 44 +++++++++++++++++++ .../pmd/lang/document/TextDocumentTest.java | 6 +-- .../pmd/lang/document/TextPos2dTest.java | 36 +++++++++++++++ .../pmd/lang/document/TextRange2dTest.java | 35 +++++++++++++++ 6 files changed, 127 insertions(+), 13 deletions(-) create mode 100644 pmd-core/src/test/java/net/sourceforge/pmd/lang/document/FileLocationTest.java create mode 100644 pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextPos2dTest.java create mode 100644 pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextRange2dTest.java diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextRange2d.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextRange2d.java index e1a2978a65..25f6d49dc8 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextRange2d.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextRange2d.java @@ -22,7 +22,7 @@ public final class TextRange2d implements Comparable { this.endLine = endLine; this.endCol = endCol; assert startCol >= 1 && startLine >= 1 && endLine >= 1 && endCol >= 1 - : "Not a valid range " + displayString(); + : "Not a valid range " + toDisplayStringWithColon(); } @@ -34,9 +34,9 @@ public final class TextRange2d implements Comparable { return TextPos2d.pos2d(endLine, endCol); } - public String displayString() { - return "(" + startCol + ", " + endCol - + ")-(" + endLine + ", " + endCol + ")"; + public String toDisplayStringWithColon() { + return getStartPos().toDisplayStringWithColon() + "-" + + getEndPos().toDisplayStringWithColon(); } public int getStartLine() { @@ -104,7 +104,8 @@ public final class TextRange2d implements Comparable { @Override public String toString() { - return "[" + getStartPos() + " - " + getEndPos() + ']'; + return "!debug only! [" + getStartPos().toTupleString() + + " - " + getEndPos().toTupleString() + ']'; } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextRegion.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextRegion.java index 1411997a6a..5b87b05386 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextRegion.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextRegion.java @@ -50,7 +50,7 @@ public final class TextRegion implements Comparable { this.startOffset = startOffset; this.length = length; - assert startOffset >= 0 && length >= 0 : "Invalid region" + parThis(); + assert startOffset >= 0 && length >= 0 : "Invalid region " + this; } /** 0-based, inclusive index. */ @@ -122,8 +122,8 @@ public final class TextRegion implements Comparable { * @throws AssertionError If the parameter cannot produce a valid region */ public TextRegion growLeft(int delta) { - assert (delta + length) >= 0 : "Left delta " + delta + " would produce a negative length region" + parThis(); - assert (startOffset - delta) >= 0 : "Left delta " + delta + " would produce a region that starts before zero" + parThis(); + assert delta + length >= 0 : "Left delta " + delta + " would produce a negative length region " + parThis(); + assert startOffset - delta >= 0 : "Left delta " + delta + " would produce a region that starts before zero " + parThis(); return new TextRegion(startOffset - delta, delta + length); } @@ -135,7 +135,7 @@ public final class TextRegion implements Comparable { * @throws AssertionError If the delta is negative and less than the length of this region */ public TextRegion growRight(int delta) { - assert (delta + length) >= 0 : "Right delta " + delta + " would produce a negative length region" + parThis(); + assert delta + length >= 0 : "Right delta " + delta + " would produce a negative length region " + parThis(); return new TextRegion(startOffset, delta + length); } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/FileLocationTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/FileLocationTest.java new file mode 100644 index 0000000000..5e9c353497 --- /dev/null +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/FileLocationTest.java @@ -0,0 +1,44 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.document; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.junit.Assert.assertEquals; + +import org.hamcrest.MatcherAssert; +import org.junit.Test; + +/** + * @author Clément Fournier + */ +public class FileLocationTest { + + @Test + public void testSimple() { + FileLocation loc = FileLocation.range("fname", TextRange2d.range2d(1, 1, 1, 2)); + assertEquals("fname", loc.getFileName()); + assertEquals(1, loc.getStartLine()); + assertEquals(1, loc.getStartColumn()); + assertEquals(1, loc.getEndLine()); + assertEquals(2, loc.getEndColumn()); + } + + @Test + public void testToString() { + FileLocation loc = FileLocation.range("fname", TextRange2d.range2d(1, 1, 1, 2)); + + assertEquals( + "line 1, column 1", + loc.startPosToString() + ); + assertEquals( + "fname:1:1", + loc.startPosToStringWithFile() + ); + + MatcherAssert.assertThat(loc.toString(), containsString("!debug only!")); + } + +} diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextDocumentTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextDocumentTest.java index b5e98928e5..983ba92b6e 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextDocumentTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextDocumentTest.java @@ -211,9 +211,7 @@ public class TextDocumentTest { public void testRegionOutOfBounds() { TextDocument doc = TextDocument.readOnlyString("bonjour\noha\ntristesse", dummyVersion); - expect.expect(AssertionError.class); - - TextRegion.isValidRegion(0, 40, doc); + assertThrows(AssertionError.class, () -> TextRegion.isValidRegion(0, 40, doc)); } // for junit params runner @@ -228,7 +226,7 @@ public class TextDocumentTest { TextDocument.readOnlyString("bonjour\n", dummyVersion), TextDocument.readOnlyString("\n", dummyVersion), TextDocument.readOnlyString("", dummyVersion), - }; + }; } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextPos2dTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextPos2dTest.java new file mode 100644 index 0000000000..4546fede17 --- /dev/null +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextPos2dTest.java @@ -0,0 +1,36 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.document; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.junit.Assert.assertEquals; + +import org.hamcrest.MatcherAssert; +import org.junit.Test; + +/** + * @author Clément Fournier + */ +public class TextPos2dTest { + + @Test + public void testToString() { + TextPos2d pos = TextPos2d.pos2d(1, 2); + assertEquals( + "line 1, column 2", + pos.toDisplayStringInEnglish() + ); + assertEquals( + "1:2", + pos.toDisplayStringWithColon() + ); + assertEquals( + "(line=1, column=2)", + pos.toTupleString() + ); + MatcherAssert.assertThat(pos.toString(), containsString("!debug only!")); + } + +} diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextRange2dTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextRange2dTest.java new file mode 100644 index 0000000000..188eb1cb7b --- /dev/null +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextRange2dTest.java @@ -0,0 +1,35 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.document; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.junit.Assert.assertEquals; + +import org.hamcrest.MatcherAssert; +import org.junit.Test; + +/** + * @author Clément Fournier + */ +public class TextRange2dTest { + + @Test + public void testCtors() { + TextRange2d pos = TextRange2d.range2d(1, 2, 3, 4); + TextRange2d pos2 = TextRange2d.range2d(TextPos2d.pos2d(1, 2), TextPos2d.pos2d(3, 4)); + assertEquals(pos, pos2); + } + + @Test + public void testToString() { + TextRange2d range = TextRange2d.range2d(1, 2, 3, 4); + assertEquals( + "1:2-3:4", + range.toDisplayStringWithColon() + ); + MatcherAssert.assertThat(range.toString(), containsString("!debug only!")); + } + +} From d0dc228b009656f31104a27d0e6ea28b368cfc55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 24 Apr 2022 16:58:42 +0200 Subject: [PATCH 120/180] Avoid calling indexOf too often in lines iterator --- .../sourceforge/pmd/lang/document/Chars.java | 70 ++++++++++++++----- .../pmd/lang/document/TextDocumentTest.java | 4 -- 2 files changed, 54 insertions(+), 20 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java index f9d4b91c1e..0b002b22d7 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java @@ -17,6 +17,7 @@ import java.util.regex.Pattern; import java.util.stream.Stream; import java.util.stream.StreamSupport; +import org.apache.commons.lang3.StringUtils; import org.checkerframework.checker.nullness.qual.NonNull; /** @@ -37,6 +38,15 @@ import org.checkerframework.checker.nullness.qual.NonNull; public final class Chars implements CharSequence { public static final Chars EMPTY = wrap(""); + /** + * Special sentinel used by {@link #lines()}. + */ + private static final int NOT_TRIED = -2; + + /** + * See {@link StringUtils#INDEX_NOT_FOUND}. + */ + private static final int NOT_FOUND = -1; private final String str; private final int start; @@ -161,20 +171,20 @@ public final class Chars implements CharSequence { final int max = start + len - searched.length(); if (fromIndex < 0 || max < start + fromIndex) { - return -1; + return NOT_FOUND; } else if (searched.isEmpty()) { return 0; } final char fst = searched.charAt(0); int strpos = str.indexOf(fst, start + fromIndex); - while (strpos != -1 && strpos <= max) { + while (strpos != NOT_FOUND && strpos <= max) { if (str.startsWith(searched, strpos)) { return strpos - start; } strpos = str.indexOf(fst, strpos + 1); } - return -1; + return NOT_FOUND; } /** @@ -182,7 +192,7 @@ public final class Chars implements CharSequence { */ public int indexOf(int ch, int fromIndex) { if (fromIndex < 0 || fromIndex >= len) { - return -1; + return NOT_FOUND; } // we want to avoid searching too far in the string // so we don't use String#indexOf, as it would be looking @@ -196,7 +206,7 @@ public final class Chars implements CharSequence { return i - start; } } - return -1; + return NOT_FOUND; } /** @@ -204,7 +214,7 @@ public final class Chars implements CharSequence { */ public int lastIndexOf(int ch, int fromIndex) { if (fromIndex < 0 || fromIndex >= len) { - return -1; + return NOT_FOUND; } // we want to avoid searching too far in the string // so we don't use String#indexOf, as it would be looking @@ -217,7 +227,7 @@ public final class Chars implements CharSequence { return i - start; } } - return -1; + return NOT_FOUND; } /** @@ -460,6 +470,12 @@ public final class Chars implements CharSequence { return () -> new Iterator() { final int max = len; int pos = 0; + // If those are NOT_TRIED, then we should scan ahead to find them + // If the scan fails then they'll stay -1 forever and won't be tried again. + // This is important to scan in documents where we know there are no + // CR characters, as in our normalized TextFileContent. + int nextCr = NOT_TRIED; + int nextLf = NOT_TRIED; @Override public boolean hasNext() { @@ -468,28 +484,50 @@ public final class Chars implements CharSequence { @Override public Chars next() { - int curPos = pos; - int cr = indexOf('\r', curPos); - int lf = indexOf('\n', curPos); + final int curPos = pos; + if (nextCr == NOT_TRIED) { + nextCr = indexOf('\r', curPos); + } + if (nextLf == NOT_TRIED) { + nextLf = indexOf('\n', curPos); + } + final int cr = nextCr; + final int lf = nextLf; - if (cr != -1 && lf != -1) { + if (cr != NOT_FOUND && lf != NOT_FOUND) { // found both CR and LF int min = Math.min(cr, lf); - pos = lf == cr + 1 ? lf + 1 // CRLF - : min + 1; + if (lf == cr + 1) { + // CRLF + pos = lf + 1; + nextCr = NOT_TRIED; + nextLf = NOT_TRIED; + } else { + pos = min + 1; + resetLookahead(cr, min); + } return subSequence(curPos, min); - } else if (cr == -1 && lf == -1) { + } else if (cr == NOT_FOUND && lf == NOT_FOUND) { // no following line terminator, cut until the end pos = max; return subSequence(curPos, max); } else { // lf or cr (exactly one is != -1 and max returns that one) int idx = Math.max(cr, lf); + resetLookahead(cr, idx); pos = idx + 1; return subSequence(curPos, idx); } } + + private void resetLookahead(int cr, int idx) { + if (idx == cr) { + nextCr = NOT_TRIED; + } else { + nextLf = NOT_TRIED; + } + } }; } @@ -515,7 +553,7 @@ public final class Chars implements CharSequence { throw new IndexOutOfBoundsException(); } if (pos >= max) { - return -1; + return NOT_FOUND; } int toRead = Integer.min(max - pos, len); str.getChars(pos, pos + toRead, cbuf, off); @@ -525,7 +563,7 @@ public final class Chars implements CharSequence { @Override public int read() { - return pos >= max ? -1 : str.charAt(pos++); + return pos >= max ? NOT_FOUND : str.charAt(pos++); } @Override diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextDocumentTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextDocumentTest.java index 983ba92b6e..a443e93189 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextDocumentTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextDocumentTest.java @@ -11,9 +11,7 @@ import static org.junit.Assert.assertThrows; import java.io.IOException; import org.apache.commons.io.IOUtils; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import net.sourceforge.pmd.lang.DummyLanguageModule; @@ -26,8 +24,6 @@ import junitparams.Parameters; @RunWith(JUnitParamsRunner.class) public class TextDocumentTest { - @Rule - public ExpectedException expect = ExpectedException.none(); private final LanguageVersion dummyVersion = LanguageRegistry.getDefaultLanguage().getDefaultVersion(); @Test From 6cf5e09088b60d5302efb61540536eba63e45184 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 24 Apr 2022 17:01:22 +0200 Subject: [PATCH 121/180] Add test for text files --- .../pmd/lang/document/TextFile.java | 19 +++- .../pmd/util/treeexport/TreeExportCli.java | 2 +- .../pmd/lang/document/TextFilesTest.java | 96 +++++++++++++++++++ 3 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextFilesTest.java diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextFile.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextFile.java index 5b7c898eef..6b7ccff057 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextFile.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextFile.java @@ -212,7 +212,24 @@ public interface TextFile extends Closeable { * * @throws NullPointerException If any parameter is null */ - static TextFileBuilder forReader(Reader reader, String pathId, LanguageVersion languageVersion) { + static TextFile forReader(Reader reader, String pathId, LanguageVersion languageVersion) { + return builderForReader(reader, pathId, languageVersion).build(); + } + + /** + * Returns a read-only builder reading from a reader. + * The reader is first read when {@link TextFile#readContents()} is first + * called, and is closed when that method exits. Note that this may + * only be called once, afterwards, {@link TextFile#readContents()} will + * throw an {@link IOException}. + * + * @param reader Text of the file + * @param pathId File name to use as path id + * @param languageVersion Language version + * + * @throws NullPointerException If any parameter is null + */ + static TextFileBuilder builderForReader(Reader reader, String pathId, LanguageVersion languageVersion) { return new ForReader(languageVersion, reader, pathId); } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/treeexport/TreeExportCli.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/treeexport/TreeExportCli.java index cdc35ff579..e8381171a1 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/treeexport/TreeExportCli.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/treeexport/TreeExportCli.java @@ -188,7 +188,7 @@ public class TreeExportCli { throw bail("One of --file or --read-stdin must be mentioned"); } else if (readStdin) { io.stderr.println("Reading from stdin..."); - textFile = TextFile.forReader(readFromSystemIn(), "stdin", langVersion).build(); + textFile = TextFile.forReader(readFromSystemIn(), "stdin", langVersion); } else { textFile = TextFile.forPath(Paths.get(file), Charset.forName(encoding), langVersion); } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextFilesTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextFilesTest.java new file mode 100644 index 0000000000..c165582980 --- /dev/null +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextFilesTest.java @@ -0,0 +1,96 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.document; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; + +import org.apache.commons.io.IOUtils; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +import net.sourceforge.pmd.lang.DummyLanguageModule; +import net.sourceforge.pmd.lang.LanguageVersion; + +public class TextFilesTest { + + @Rule + public TemporaryFolder tempDir = TemporaryFolder.builder().build(); + + private LanguageVersion dummyVersion = DummyLanguageModule.getInstance().getDefaultVersion(); + + @Test + public void testNioFile() throws IOException { + Path file = makeTmpFile(StandardCharsets.UTF_8, "some content"); + try (TextFile tf = TextFile.forPath(file, StandardCharsets.UTF_8, dummyVersion)) { + Assert.assertEquals(file.toAbsolutePath().toString(), tf.getPathId()); + Assert.assertEquals(file.toString(), tf.getDisplayName()); + Assert.assertEquals(dummyVersion, tf.getLanguageVersion()); + Assert.assertEquals(Chars.wrap("some content"), tf.readContents().getNormalizedText()); + } + } + + @Test + public void testNioFileBuilder() throws IOException { + Path file = makeTmpFile(StandardCharsets.UTF_8, "some content"); + try (TextFile tf = TextFile.builderForPath(file, StandardCharsets.UTF_8, dummyVersion) + .withDisplayName("aname") + .build()) { + Assert.assertEquals(file.toAbsolutePath().toString(), tf.getPathId()); + Assert.assertEquals("aname", tf.getDisplayName()); + Assert.assertEquals(dummyVersion, tf.getLanguageVersion()); + Assert.assertEquals(Chars.wrap("some content"), tf.readContents().getNormalizedText()); + } + } + + @Test + public void testNioFileEscape() throws IOException { + Path file = makeTmpFile(StandardCharsets.UTF_8, "some\r\ncontent"); + try (TextFile tf = TextFile.forPath(file, StandardCharsets.UTF_8, dummyVersion)) { + Assert.assertEquals(Chars.wrap("some\ncontent"), tf.readContents().getNormalizedText()); + } + } + + @Test + public void testReaderFileEscape() throws IOException { + Path file = makeTmpFile(StandardCharsets.UTF_8, "some\r\ncontent"); + try (TextFile tf = TextFile.forReader(Files.newBufferedReader(file, StandardCharsets.UTF_8), "filename", dummyVersion)) { + Assert.assertEquals("filename", tf.getPathId()); + Assert.assertEquals("filename", tf.getDisplayName()); + Assert.assertEquals(dummyVersion, tf.getLanguageVersion()); + Assert.assertEquals(Chars.wrap("some\ncontent"), tf.readContents().getNormalizedText()); + Assert.assertThrows(ReadOnlyFileException.class, () -> tf.writeContents( + TextFileContent.fromCharSeq("new content") + )); + } + }@Test + public void testStringFileEscape() throws IOException { + try (TextFile tf = TextFile.forCharSeq("cont\r\nents", "filename", dummyVersion)) { + Assert.assertEquals("filename", tf.getPathId()); + Assert.assertEquals("filename", tf.getDisplayName()); + Assert.assertEquals(dummyVersion, tf.getLanguageVersion()); + Assert.assertEquals(Chars.wrap("cont\r\nent"), tf.readContents().getNormalizedText()); + Assert.assertThrows(ReadOnlyFileException.class, () -> tf.writeContents( + TextFileContent.fromCharSeq("new content") + )); + } + } + + private @NonNull Path makeTmpFile(Charset charset, String content) throws IOException { + Path file = tempDir.newFile().toPath(); + try (BufferedWriter writer = Files.newBufferedWriter(file, charset)) { + IOUtils.write(content, writer); + } + return file; + } + +} From dae31bf3085ea329eb40f9ef3d11defaae879973 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 24 Apr 2022 17:11:33 +0200 Subject: [PATCH 122/180] Tests for readonlyness --- .../pmd/lang/document/FileCollector.java | 12 +- .../pmd/lang/document/NioTextFile.java | 13 ++- .../pmd/lang/document/TextFileBuilder.java | 57 ++++++---- .../pmd/lang/document/TextFilesTest.java | 103 ++++++++++++++---- 4 files changed, 139 insertions(+), 46 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/FileCollector.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/FileCollector.java index ef8867dee5..460a56537a 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/FileCollector.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/FileCollector.java @@ -48,6 +48,7 @@ import net.sourceforge.pmd.util.log.MessageReporter; */ @SuppressWarnings("PMD.CloseResource") public final class FileCollector implements AutoCloseable { + private static final Logger LOG = LoggerFactory.getLogger(FileCollector.class); private final List allFilesToProcess = new ArrayList<>(); @@ -167,8 +168,11 @@ public final class FileCollector implements AutoCloseable { reporter.error("Not a regular file {}", file); return false; } - NioTextFile nioTextFile = new NioTextFile(file, charset, discoverer.getDefaultLanguageVersion(language), getDisplayName(file)); - addFileImpl(nioTextFile); + LanguageVersion lv = discoverer.getDefaultLanguageVersion(language); + Objects.requireNonNull(lv); + addFileImpl(TextFile.builderForPath(file, charset, lv) + .withDisplayName(getDisplayName(file)) + .build()); return true; } @@ -371,7 +375,7 @@ public final class FileCollector implements AutoCloseable { */ public void exclude(FileCollector excludeCollector) { Set toExclude = new HashSet<>(excludeCollector.allFilesToProcess); - for (Iterator iterator = allFilesToProcess.iterator(); iterator.hasNext();) { + for (Iterator iterator = allFilesToProcess.iterator(); iterator.hasNext(); ) { TextFile file = iterator.next(); if (toExclude.contains(file)) { LOG.trace("Excluding file {}", file.getPathId()); @@ -385,7 +389,7 @@ public final class FileCollector implements AutoCloseable { * collection. */ public void filterLanguages(Set languages) { - for (Iterator iterator = allFilesToProcess.iterator(); iterator.hasNext();) { + for (Iterator iterator = allFilesToProcess.iterator(); iterator.hasNext(); ) { TextFile file = iterator.next(); Language lang = file.getLanguageVersion().getLanguage(); if (!languages.contains(lang)) { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/NioTextFile.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/NioTextFile.java index 21f96da6d7..f362a231cc 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/NioTextFile.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/NioTextFile.java @@ -27,13 +27,19 @@ class NioTextFile extends BaseCloseable implements TextFile { private final Charset charset; private final LanguageVersion languageVersion; private final @Nullable String displayName; + private boolean readOnly; - NioTextFile(Path path, Charset charset, LanguageVersion languageVersion, @Nullable String displayName) { + NioTextFile(Path path, + Charset charset, + LanguageVersion languageVersion, + @Nullable String displayName, + boolean readOnly) { AssertionUtil.requireParamNotNull("path", path); AssertionUtil.requireParamNotNull("charset", charset); AssertionUtil.requireParamNotNull("language version", languageVersion); this.displayName = displayName; + this.readOnly = readOnly; this.path = path; this.charset = charset; this.languageVersion = languageVersion; @@ -56,12 +62,15 @@ class NioTextFile extends BaseCloseable implements TextFile { @Override public boolean isReadOnly() { - return !Files.isWritable(path); + return readOnly || !Files.isWritable(path); } @Override public void writeContents(TextFileContent content) throws IOException { ensureOpen(); + if (isReadOnly()) { + throw new ReadOnlyFileException(); + } try (BufferedWriter bw = Files.newBufferedWriter(path, charset)) { if (content.getLineTerminator().equals(TextFileContent.NORMALIZED_LINE_TERM)) { content.getNormalizedText().writeFully(bw); diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextFileBuilder.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextFileBuilder.java index 2c1e066f10..f240b51b81 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextFileBuilder.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextFileBuilder.java @@ -26,10 +26,41 @@ public abstract class TextFileBuilder { this.languageVersion = AssertionUtil.requireParamNotNull("language version", languageVersion); } + /** + * Specify that the built file is read only. Some text files are + * always read-only. + * + * @return This builder + */ + public TextFileBuilder asReadOnly() { + // default is appropriate if the file type is always read-only + return this; + } + + + /** + * Sets a custom display name for the new file. If null, or this is + * never called, the display name defaults to the path ID. + * + * @param displayName A display name + * + * @return This builder + */ + public TextFileBuilder withDisplayName(@Nullable String displayName) { + this.displayName = displayName; + return this; + } + + /** + * Creates and returns the new text file. + */ + public abstract TextFile build(); + static class ForNio extends TextFileBuilder { private final Path path; private final Charset charset; + private boolean readOnly = false; ForNio(LanguageVersion languageVersion, Path path, Charset charset) { super(languageVersion); @@ -37,9 +68,15 @@ public abstract class TextFileBuilder { this.charset = AssertionUtil.requireParamNotNull("charset", charset); } + @Override + public TextFileBuilder asReadOnly() { + readOnly = true; + return this; + } + @Override public TextFile build() { - return new NioTextFile(path, charset, languageVersion, displayName); + return new NioTextFile(path, charset, languageVersion, displayName, readOnly); } } @@ -77,22 +114,4 @@ public abstract class TextFileBuilder { } } - - /** - * Sets a custom display name for the new file. If null, or this is - * never called, the display name defaults to the path ID. - * - * @param displayName A display name - * - * @return This builder - */ - public TextFileBuilder withDisplayName(@Nullable String displayName) { - this.displayName = displayName; - return this; - } - - /** - * Creates and returns the new text file. - */ - public abstract TextFile build(); } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextFilesTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextFilesTest.java index c165582980..a53ec06ef8 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextFilesTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextFilesTest.java @@ -4,6 +4,11 @@ package net.sourceforge.pmd.lang.document; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; + import java.io.BufferedWriter; import java.io.IOException; import java.nio.charset.Charset; @@ -13,7 +18,6 @@ import java.nio.file.Path; import org.apache.commons.io.IOUtils; import org.checkerframework.checker.nullness.qual.NonNull; -import org.junit.Assert; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; @@ -32,10 +36,47 @@ public class TextFilesTest { public void testNioFile() throws IOException { Path file = makeTmpFile(StandardCharsets.UTF_8, "some content"); try (TextFile tf = TextFile.forPath(file, StandardCharsets.UTF_8, dummyVersion)) { - Assert.assertEquals(file.toAbsolutePath().toString(), tf.getPathId()); - Assert.assertEquals(file.toString(), tf.getDisplayName()); - Assert.assertEquals(dummyVersion, tf.getLanguageVersion()); - Assert.assertEquals(Chars.wrap("some content"), tf.readContents().getNormalizedText()); + assertEquals(file.toAbsolutePath().toString(), tf.getPathId()); + assertEquals(file.toString(), tf.getDisplayName()); + assertEquals(dummyVersion, tf.getLanguageVersion()); + assertEquals(Chars.wrap("some content"), tf.readContents().getNormalizedText()); + } + } + + @Test + public void testNioFileWrite() throws IOException { + Path file = makeTmpFile(StandardCharsets.UTF_8, "some content"); + try (TextFile tf = TextFile.forPath(file, StandardCharsets.UTF_8, dummyVersion)) { + assertEquals(Chars.wrap("some content"), tf.readContents().getNormalizedText()); + assertFalse("readonly", tf.isReadOnly()); + + tf.writeContents( + TextFileContent.fromCharSeq("new content") + ); + + assertEquals(Chars.wrap("new content"), tf.readContents().getNormalizedText()); + } + } + + @Test + public void testNioFileExplicitReadOnly() throws IOException { + Path file = makeTmpFile(StandardCharsets.UTF_8, "some content"); + try (TextFile tf = TextFile.builderForPath(file, StandardCharsets.UTF_8, dummyVersion) + .asReadOnly().build()) { + assertTrue("readonly", tf.isReadOnly()); + + assertThrows(ReadOnlyFileException.class, () -> tf.writeContents( + TextFileContent.fromCharSeq("new content") + )); + } + } + + @Test + public void testNioFileCanBeReadMultipleTimes() throws IOException { + Path file = makeTmpFile(StandardCharsets.UTF_8, "some content"); + try (TextFile tf = TextFile.forPath(file, StandardCharsets.UTF_8, dummyVersion)) { + assertEquals(Chars.wrap("some content"), tf.readContents().getNormalizedText()); + assertEquals(Chars.wrap("some content"), tf.readContents().getNormalizedText()); } } @@ -45,10 +86,10 @@ public class TextFilesTest { try (TextFile tf = TextFile.builderForPath(file, StandardCharsets.UTF_8, dummyVersion) .withDisplayName("aname") .build()) { - Assert.assertEquals(file.toAbsolutePath().toString(), tf.getPathId()); - Assert.assertEquals("aname", tf.getDisplayName()); - Assert.assertEquals(dummyVersion, tf.getLanguageVersion()); - Assert.assertEquals(Chars.wrap("some content"), tf.readContents().getNormalizedText()); + assertEquals(file.toAbsolutePath().toString(), tf.getPathId()); + assertEquals("aname", tf.getDisplayName()); + assertEquals(dummyVersion, tf.getLanguageVersion()); + assertEquals(Chars.wrap("some content"), tf.readContents().getNormalizedText()); } } @@ -56,7 +97,7 @@ public class TextFilesTest { public void testNioFileEscape() throws IOException { Path file = makeTmpFile(StandardCharsets.UTF_8, "some\r\ncontent"); try (TextFile tf = TextFile.forPath(file, StandardCharsets.UTF_8, dummyVersion)) { - Assert.assertEquals(Chars.wrap("some\ncontent"), tf.readContents().getNormalizedText()); + assertEquals(Chars.wrap("some\ncontent"), tf.readContents().getNormalizedText()); } } @@ -64,22 +105,42 @@ public class TextFilesTest { public void testReaderFileEscape() throws IOException { Path file = makeTmpFile(StandardCharsets.UTF_8, "some\r\ncontent"); try (TextFile tf = TextFile.forReader(Files.newBufferedReader(file, StandardCharsets.UTF_8), "filename", dummyVersion)) { - Assert.assertEquals("filename", tf.getPathId()); - Assert.assertEquals("filename", tf.getDisplayName()); - Assert.assertEquals(dummyVersion, tf.getLanguageVersion()); - Assert.assertEquals(Chars.wrap("some\ncontent"), tf.readContents().getNormalizedText()); - Assert.assertThrows(ReadOnlyFileException.class, () -> tf.writeContents( + assertEquals("filename", tf.getPathId()); + assertEquals("filename", tf.getDisplayName()); + assertEquals(dummyVersion, tf.getLanguageVersion()); + assertEquals(Chars.wrap("some\ncontent"), tf.readContents().getNormalizedText()); + assertThrows(ReadOnlyFileException.class, () -> tf.writeContents( TextFileContent.fromCharSeq("new content") )); } - }@Test + } + + @Test public void testStringFileEscape() throws IOException { try (TextFile tf = TextFile.forCharSeq("cont\r\nents", "filename", dummyVersion)) { - Assert.assertEquals("filename", tf.getPathId()); - Assert.assertEquals("filename", tf.getDisplayName()); - Assert.assertEquals(dummyVersion, tf.getLanguageVersion()); - Assert.assertEquals(Chars.wrap("cont\r\nent"), tf.readContents().getNormalizedText()); - Assert.assertThrows(ReadOnlyFileException.class, () -> tf.writeContents( + assertEquals("filename", tf.getPathId()); + assertEquals("filename", tf.getDisplayName()); + assertEquals(dummyVersion, tf.getLanguageVersion()); + assertEquals(Chars.wrap("cont\nents"), tf.readContents().getNormalizedText()); + assertThrows(ReadOnlyFileException.class, () -> tf.writeContents( + TextFileContent.fromCharSeq("new content") + )); + } + } + + @Test + public void testStringFileCanBeReadMultipleTimes() throws IOException { + try (TextFile tf = TextFile.forCharSeq("contents", "filename", dummyVersion)) { + assertEquals(Chars.wrap("contents"), tf.readContents().getNormalizedText()); + assertEquals(Chars.wrap("contents"), tf.readContents().getNormalizedText()); + assertEquals(Chars.wrap("contents"), tf.readContents().getNormalizedText()); + } + } + + @Test + public void testStringFileIsReadonly() throws IOException { + try (TextFile tf = TextFile.forCharSeq("contents", "filename", dummyVersion)) { + assertThrows(ReadOnlyFileException.class, () -> tf.writeContents( TextFileContent.fromCharSeq("new content") )); } From 996f81ccce4645cee1086392df05d469d6fb1e2c Mon Sep 17 00:00:00 2001 From: HoshiNoMei <11910516@mail.sustech.edu.cn> Date: Sun, 24 Apr 2022 23:36:46 +0800 Subject: [PATCH 123/180] Modify the rule to meet the missing case --- .../src/main/resources/category/java/design.xml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/pmd-java/src/main/resources/category/java/design.xml b/pmd-java/src/main/resources/category/java/design.xml index f071a261f9..1835882366 100644 --- a/pmd-java/src/main/resources/category/java/design.xml +++ b/pmd-java/src/main/resources/category/java/design.xml @@ -1289,7 +1289,8 @@ public void foo() throws Exception { 3 @@ -1308,6 +1314,8 @@ or //ConditionalExpression[not(PrimaryExpression/*/Literal) and (Expression/PrimaryExpression/*/Literal/BooleanLiteral)] | //ConditionalExpression[not(Expression/PrimaryExpression/*/Literal) and (PrimaryExpression/*/Literal/BooleanLiteral)] +| +//ConditionalExpression[(PrimaryExpression/*/Literal/BooleanLiteral) and (Expression/PrimaryExpression/*/Literal/BooleanLiteral)] ]]>
@@ -1330,6 +1338,10 @@ public class Foo { public void test4() { final boolean otherValue = condition ? something() : false; // can be as simple as condition && something(); } + + public boolean test5() { + return condition ? true : false; // can be as simple as return condition; + } } ]]> From dc40bc27b8b8c09f7982fd8eafe7bd723feb94d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 24 Apr 2022 17:38:35 +0200 Subject: [PATCH 124/180] More tests --- .../pmd/lang/document/NioTextFile.java | 2 +- .../lang/document/ReadOnlyFileException.java | 4 ++ .../pmd/lang/document/TextFile.java | 2 +- .../pmd/lang/document/TextFileContent.java | 19 +++--- .../pmd/lang/document/TextPos2d.java | 6 +- .../pmd/lang/document/TextRange2d.java | 12 ++-- .../document/internal/LanguageDiscoverer.java | 63 ------------------- .../pmd/lang/document/FileLocationTest.java | 7 +++ .../document/SourceCodePositionerTest.java | 4 ++ .../pmd/lang/document/TextFilesTest.java | 26 +++++++- .../pmd/lang/document/TextPos2dTest.java | 22 +++++++ .../pmd/lang/document/TextRange2dTest.java | 20 ++++++ 12 files changed, 102 insertions(+), 85 deletions(-) delete mode 100644 pmd-core/src/main/java/net/sourceforge/pmd/lang/document/internal/LanguageDiscoverer.java diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/NioTextFile.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/NioTextFile.java index f362a231cc..c0400e9294 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/NioTextFile.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/NioTextFile.java @@ -69,7 +69,7 @@ class NioTextFile extends BaseCloseable implements TextFile { public void writeContents(TextFileContent content) throws IOException { ensureOpen(); if (isReadOnly()) { - throw new ReadOnlyFileException(); + throw new ReadOnlyFileException(this); } try (BufferedWriter bw = Files.newBufferedWriter(path, charset)) { if (content.getLineTerminator().equals(TextFileContent.NORMALIZED_LINE_TERM)) { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/ReadOnlyFileException.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/ReadOnlyFileException.java index 28b739c21c..df27cb13c1 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/ReadOnlyFileException.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/ReadOnlyFileException.java @@ -10,4 +10,8 @@ package net.sourceforge.pmd.lang.document; */ public class ReadOnlyFileException extends UnsupportedOperationException { + public ReadOnlyFileException(TextFile textFile) { + super("Read only: " + textFile.getPathId()); + } + } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextFile.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextFile.java index 6b7ccff057..83ab966a47 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextFile.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextFile.java @@ -109,7 +109,7 @@ public interface TextFile extends Closeable { * @throws ReadOnlyFileException If this text source is read-only */ default void writeContents(TextFileContent content) throws IOException { - throw new ReadOnlyFileException(); + throw new ReadOnlyFileException(this); } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextFileContent.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextFileContent.java index 0d4234c5ae..cb77db852c 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextFileContent.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextFileContent.java @@ -30,11 +30,16 @@ import org.checkerframework.checker.nullness.qual.Nullable; */ public final class TextFileContent { + // the three line terminators we handle. + private static final String CRLF = "\r\n"; + private static final String LF = "\n"; + private static final String CR = "\r"; + /** * The normalized line ending used to replace platform-specific * line endings in the {@linkplain #getNormalizedText() normalized text}. */ - public static final String NORMALIZED_LINE_TERM = "\n"; + public static final String NORMALIZED_LINE_TERM = LF; /** The normalized line ending as a char. */ public static final char NORMALIZED_LINE_TERM_CHAR = '\n'; @@ -225,10 +230,10 @@ public final class TextFileContent { if (afterCr && c != NORMALIZED_LINE_TERM_CHAR) { // we saw a \r last iteration, but didn't copy it // it's not followed by an \n - newLineTerm = "\r"; + newLineTerm = CR; newLineOffset = bufOffset + i + offsetDiff; if (i > 0) { - cbuf[i - 1] = '\n'; // replace the \r with a \n + cbuf[i - 1] = NORMALIZED_LINE_TERM_CHAR; // replace the \r with a \n } else { // The CR was trailing a buffer, so it's not in the current buffer and wasn't copied. // Append a newline. @@ -236,10 +241,10 @@ public final class TextFileContent { } } else { if (afterCr) { - newLineTerm = "\r\n"; + newLineTerm = CRLF; if (i > 0) { - cbuf[i - 1] = '\n'; // replace the \r with a \n + cbuf[i - 1] = NORMALIZED_LINE_TERM_CHAR; // replace the \r with a \n // copy up to and including the \r, which was replaced result.append(cbuf, nextCharToCopy, i - nextCharToCopy); nextCharToCopy = i + 1; // set the next char to copy to after the \n @@ -249,7 +254,7 @@ public final class TextFileContent { offsetDiff--; } else { // just \n - newLineTerm = "\n"; + newLineTerm = LF; } newLineOffset = bufOffset + i + offsetDiff + 1; } @@ -275,7 +280,7 @@ public final class TextFileContent { if (afterCr) { // we're at EOF, so it's not followed by \n result.append(NORMALIZED_LINE_TERM); positionerBuilder.addLineEndAtOffset(bufOffset); - detectedLineTerm = detectLineTerm(detectedLineTerm, "\r", fallbackLineSep); + detectedLineTerm = detectLineTerm(detectedLineTerm, CR, fallbackLineSep); } if (detectedLineTerm == null) { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextPos2d.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextPos2d.java index bdf767af3b..b554cd3eda 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextPos2d.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextPos2d.java @@ -18,7 +18,7 @@ public final class TextPos2d implements Comparable { this.line = line; this.column = column; - assert line > 0 && column > 0 : "Invalid position" + parThis(); + assert line > 0 && column > 0 : "Invalid position " + toTupleString(); } /** @@ -44,10 +44,6 @@ public final class TextPos2d implements Comparable { return new TextPos2d(line, column); } - private String parThis() { - return "(" + this + ")"; - } - /** Compares the start offset, then the length of a region. */ @Override diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextRange2d.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextRange2d.java index 25f6d49dc8..14519896a9 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextRange2d.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextRange2d.java @@ -4,12 +4,18 @@ package net.sourceforge.pmd.lang.document; +import java.util.Comparator; import java.util.Objects; /** * A place in a text document, represented as line/column information. */ public final class TextRange2d implements Comparable { + private static final Comparator COMPARATOR = + Comparator.comparingInt(TextRange2d::getStartLine) + .thenComparingInt(TextRange2d::getStartColumn) + .thenComparingInt(TextRange2d::getEndLine) + .thenComparingInt(TextRange2d::getEndColumn); private final int startLine; private final int startCol; @@ -69,11 +75,7 @@ public final class TextRange2d implements Comparable { @Override public int compareTo(TextRange2d o) { - int cmp = getStartPos().compareTo(o.getStartPos()); - if (cmp != 0) { - return cmp; - } - return getEndPos().compareTo(o.getEndPos()); + return COMPARATOR.compare(this, o); } public boolean contains(TextRange2d range) { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/internal/LanguageDiscoverer.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/internal/LanguageDiscoverer.java deleted file mode 100644 index 0544cc175c..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/internal/LanguageDiscoverer.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.document.internal; - -import java.nio.file.Path; -import java.util.Collections; -import java.util.List; - -import org.apache.commons.lang3.StringUtils; - -import net.sourceforge.pmd.lang.Language; -import net.sourceforge.pmd.lang.LanguageRegistry; - -/** - * Discovers the languages applicable to a file. - */ -public class LanguageDiscoverer { - - - private final Language forcedLanguage; - - /** - * Build a new instance. - * - * @param forcedLanguage If non-null, all files will be assigned this language. - */ - public LanguageDiscoverer(Language forcedLanguage) { - this.forcedLanguage = forcedLanguage; - } - - /** - * Get the Languages of a given source file. - * - * @param sourceFile The file. - * - * @return The Languages for the source file, may be empty. - */ - public List getLanguagesForFile(Path sourceFile) { - return getLanguagesForFile(sourceFile.getFileName().toString()); - } - - /** - * Get the Languages of a given source file. - * - * @param fileName The file name. - * - * @return The Languages for the source file, may be empty. - */ - public List getLanguagesForFile(String fileName) { - if (forcedLanguage != null) { - return Collections.singletonList(forcedLanguage); - } - String extension = getExtension(fileName); - return LanguageRegistry.findByExtension(extension); - } - - // Get the extensions from a file - private String getExtension(String fileName) { - return StringUtils.substringAfterLast(fileName, "."); - } -} diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/FileLocationTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/FileLocationTest.java index 5e9c353497..d0fb1e31d2 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/FileLocationTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/FileLocationTest.java @@ -25,6 +25,13 @@ public class FileLocationTest { assertEquals(2, loc.getEndColumn()); } + @Test + public void testToRange() { + TextRange2d range2d = TextRange2d.range2d(1, 1, 1, 2); + FileLocation loc = FileLocation.range("fname", range2d); + assertEquals(range2d, loc.toRange2d()); + } + @Test public void testToString() { FileLocation loc = FileLocation.range("fname", TextRange2d.range2d(1, 1, 1, 2)); diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/SourceCodePositionerTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/SourceCodePositionerTest.java index 5436b626bf..26a3c987c2 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/SourceCodePositionerTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/SourceCodePositionerTest.java @@ -63,6 +63,10 @@ public class SourceCodePositionerTest { assertEquals("abcd\ndef".length(), positioner.offsetFromLineColumn(2, 4)); assertEquals("abcd\ndefghi\r\n".length(), positioner.offsetFromLineColumn(3, 1)); + assertEquals(source.length(), positioner.offsetFromLineColumn(4, 4)); + assertEquals(-1, positioner.offsetFromLineColumn(4, 5)); + assertEquals(source.length(), positioner.offsetFromLineColumn(5, 1)); + assertEquals(-1, positioner.offsetFromLineColumn(5, 2)); } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextFilesTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextFilesTest.java index a53ec06ef8..fe807c00cb 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextFilesTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextFilesTest.java @@ -50,11 +50,22 @@ public class TextFilesTest { assertEquals(Chars.wrap("some content"), tf.readContents().getNormalizedText()); assertFalse("readonly", tf.isReadOnly()); + // write with CRLF tf.writeContents( - TextFileContent.fromCharSeq("new content") + TextFileContent.fromCharSeq("new content\r\n") ); - assertEquals(Chars.wrap("new content"), tf.readContents().getNormalizedText()); + TextFileContent read = tf.readContents(); + // is normalized to LF when rereading + assertEquals(Chars.wrap("new content\n"), read.getNormalizedText()); + // but line terminator is detected as CRLF + assertEquals("\r\n", read.getLineTerminator()); + + tf.writeContents( + TextFileContent.fromCharSeq("new content\n") + ); + + assertEquals(Chars.wrap("new content\n"), tf.readContents().getNormalizedText()); } } @@ -102,13 +113,21 @@ public class TextFilesTest { } @Test - public void testReaderFileEscape() throws IOException { + public void testReaderFile() throws IOException { Path file = makeTmpFile(StandardCharsets.UTF_8, "some\r\ncontent"); try (TextFile tf = TextFile.forReader(Files.newBufferedReader(file, StandardCharsets.UTF_8), "filename", dummyVersion)) { assertEquals("filename", tf.getPathId()); assertEquals("filename", tf.getDisplayName()); assertEquals(dummyVersion, tf.getLanguageVersion()); assertEquals(Chars.wrap("some\ncontent"), tf.readContents().getNormalizedText()); + } + } + + @Test + public void testReaderFileIsReadOnly() throws IOException { + Path file = makeTmpFile(StandardCharsets.UTF_8, "some\r\ncontent"); + try (TextFile tf = TextFile.forReader(Files.newBufferedReader(file, StandardCharsets.UTF_8), "filename", dummyVersion)) { + assertTrue("readonly", tf.isReadOnly()); assertThrows(ReadOnlyFileException.class, () -> tf.writeContents( TextFileContent.fromCharSeq("new content") )); @@ -140,6 +159,7 @@ public class TextFilesTest { @Test public void testStringFileIsReadonly() throws IOException { try (TextFile tf = TextFile.forCharSeq("contents", "filename", dummyVersion)) { + assertTrue("readonly", tf.isReadOnly()); assertThrows(ReadOnlyFileException.class, () -> tf.writeContents( TextFileContent.fromCharSeq("new content") )); diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextPos2dTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextPos2dTest.java index 4546fede17..7b4e6165f9 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextPos2dTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextPos2dTest.java @@ -6,6 +6,7 @@ package net.sourceforge.pmd.lang.document; import static org.hamcrest.CoreMatchers.containsString; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; import org.hamcrest.MatcherAssert; import org.junit.Test; @@ -33,4 +34,25 @@ public class TextPos2dTest { MatcherAssert.assertThat(pos.toString(), containsString("!debug only!")); } + @Test + public void testEquals() { + TextPos2d pos = TextPos2d.pos2d(1, 1); + TextPos2d pos2 = TextPos2d.pos2d(1, 2); + assertNotEquals(pos, pos2); + assertEquals(pos, TextPos2d.pos2d(1, 1)); + assertEquals(pos2, pos2); + } + + @Test + public void testCompareTo() { + TextPos2d pos = TextPos2d.pos2d(1, 1); + TextPos2d pos2 = TextPos2d.pos2d(1, 2); + TextPos2d pos3 = TextPos2d.pos2d(2, 1); + + assertEquals(-1, pos.compareTo(pos2)); + assertEquals(-1, pos.compareTo(pos3)); + assertEquals(-1, pos2.compareTo(pos3)); + assertEquals(1, pos2.compareTo(pos)); + assertEquals(0, pos.compareTo(pos)); + } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextRange2dTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextRange2dTest.java index 188eb1cb7b..ed5f067fd8 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextRange2dTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextRange2dTest.java @@ -6,6 +6,7 @@ package net.sourceforge.pmd.lang.document; import static org.hamcrest.CoreMatchers.containsString; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; import org.hamcrest.MatcherAssert; import org.junit.Test; @@ -22,6 +23,25 @@ public class TextRange2dTest { assertEquals(pos, pos2); } + @Test + public void testEquals() { + TextRange2d pos = TextRange2d.range2d(1, 1, 1, 1); + TextRange2d pos2 = TextRange2d.range2d(1, 1, 1, 2); + assertNotEquals(pos, pos2); + assertEquals(pos, pos); + assertEquals(pos2, pos2); + } + + @Test + public void testCompareTo() { + TextRange2d pos = TextRange2d.range2d(1, 1, 1, 1); + TextRange2d pos2 = TextRange2d.range2d(1, 1, 1, 2); + + assertEquals(-1, pos.compareTo(pos2)); + assertEquals(1, pos2.compareTo(pos)); + assertEquals(0, pos.compareTo(pos)); + } + @Test public void testToString() { TextRange2d range = TextRange2d.range2d(1, 2, 3, 4); From 5bbc3fa8d1e919cfd39a77b17a3b3b97fb1dea86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 24 Apr 2022 17:56:40 +0200 Subject: [PATCH 125/180] Test data source compat --- .../net/sourceforge/pmd/PMDConfiguration.java | 2 +- .../pmd/lang/document/FileCollector.java | 4 +- .../pmd/lang/document/TextFile.java | 9 ++- .../pmd/lang/document/TextFilesTest.java | 62 +++++++++++++++++++ 4 files changed, 72 insertions(+), 5 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/PMDConfiguration.java b/pmd-core/src/main/java/net/sourceforge/pmd/PMDConfiguration.java index 72a0e6376f..589f8b2241 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/PMDConfiguration.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/PMDConfiguration.java @@ -364,7 +364,7 @@ public class PMDConfiguration extends AbstractConfiguration { if (languageVersion == null) { // For compatibility with older code that does not always pass in // a correct filename. - languageVersion = languageVersionDiscoverer.getDefaultLanguageVersion(LanguageRegistry.getLanguage("Java")); + languageVersion = languageVersionDiscoverer.getDefaultLanguageVersion(LanguageRegistry.getDefaultLanguage()); } return languageVersion; } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/FileCollector.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/FileCollector.java index 460a56537a..5e481ca5cd 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/FileCollector.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/FileCollector.java @@ -375,7 +375,7 @@ public final class FileCollector implements AutoCloseable { */ public void exclude(FileCollector excludeCollector) { Set toExclude = new HashSet<>(excludeCollector.allFilesToProcess); - for (Iterator iterator = allFilesToProcess.iterator(); iterator.hasNext(); ) { + for (Iterator iterator = allFilesToProcess.iterator(); iterator.hasNext();) { TextFile file = iterator.next(); if (toExclude.contains(file)) { LOG.trace("Excluding file {}", file.getPathId()); @@ -389,7 +389,7 @@ public final class FileCollector implements AutoCloseable { * collection. */ public void filterLanguages(Set languages) { - for (Iterator iterator = allFilesToProcess.iterator(); iterator.hasNext(); ) { + for (Iterator iterator = allFilesToProcess.iterator(); iterator.hasNext();) { TextFile file = iterator.next(); Language lang = file.getLanguageVersion().getLanguage(); if (!languages.contains(lang)) { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextFile.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextFile.java index 83ab966a47..15e3ed3c37 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextFile.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextFile.java @@ -244,16 +244,21 @@ public interface TextFile extends Closeable { @Deprecated @DeprecatedUntil700 static TextFile dataSourceCompat(DataSource ds, PMDConfiguration config) { + String pathId = ds.getNiceFileName(false, null); + LanguageVersion languageVersion = config.getLanguageVersionOfFile(pathId); + if (languageVersion == null) { + throw new NullPointerException("no language version detected for " + pathId); + } class DataSourceTextFile extends BaseCloseable implements TextFile { @Override public @NonNull LanguageVersion getLanguageVersion() { - return config.getLanguageVersionOfFile(getPathId()); + return languageVersion; } @Override public String getPathId() { - return ds.getNiceFileName(false, null); + return pathId; } @Override diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextFilesTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextFilesTest.java index fe807c00cb..a694a213b2 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextFilesTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextFilesTest.java @@ -6,6 +6,7 @@ package net.sourceforge.pmd.lang.document; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; @@ -22,8 +23,11 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; +import net.sourceforge.pmd.PMDConfiguration; import net.sourceforge.pmd.lang.DummyLanguageModule; import net.sourceforge.pmd.lang.LanguageVersion; +import net.sourceforge.pmd.util.datasource.DataSource; +import net.sourceforge.pmd.util.datasource.FileDataSource; public class TextFilesTest { @@ -43,6 +47,64 @@ public class TextFilesTest { } } + @Test + public void testEquals() throws IOException { + Path file = makeTmpFile(StandardCharsets.UTF_8, "some content").toAbsolutePath(); + try (TextFile tf = TextFile.forPath(file, StandardCharsets.UTF_8, dummyVersion)) { + try (TextFile tf2 = TextFile.forCharSeq("some content", file.toString(), dummyVersion)) { + assertEquals(tf.getPathId(), tf2.getPathId()); + + assertNotEquals(tf, tf2); + assertNotEquals(tf2, tf); + assertEquals(tf, tf); + assertEquals(tf, TextFile.forPath(file, StandardCharsets.UTF_8, dummyVersion)); + } + } + } + + @Test + public void testStringDataSourceCompat() throws IOException { + DataSource ds = DataSource.forString("text", "filename.dummy"); + PMDConfiguration config = new PMDConfiguration(); + try (TextFile tf = TextFile.dataSourceCompat(ds, config)) { + assertEquals("filename.dummy", tf.getPathId()); + assertEquals("filename.dummy", tf.getDisplayName()); + assertEquals(DummyLanguageModule.getInstance().getDefaultVersion(), tf.getLanguageVersion()); + assertEquals(Chars.wrap("text"), tf.readContents().getNormalizedText()); + } + } + + @Test + public void testFileDataSourceCompat() throws IOException { + Path file = makeTmpFile(StandardCharsets.UTF_8, "some content"); + + DataSource ds = new FileDataSource(file.toFile()); + PMDConfiguration config = new PMDConfiguration(); + try (TextFile tf = TextFile.dataSourceCompat(ds, config)) { + assertEquals(ds.getNiceFileName(false, null), tf.getPathId()); + assertEquals(ds.getNiceFileName(false, null), tf.getDisplayName()); + assertEquals(Chars.wrap("some content"), tf.readContents().getNormalizedText()); + } + } + + @Test + public void testFileDataSourceCompatWithEncoding() throws IOException { + Path file = makeTmpFile(StandardCharsets.UTF_16BE, "some content"); + + DataSource ds = new FileDataSource(file.toFile()); + PMDConfiguration config = new PMDConfiguration(); + config.setSourceEncoding(StandardCharsets.UTF_16BE.name()); + try (TextFile tf = TextFile.dataSourceCompat(ds, config)) { + assertEquals(Chars.wrap("some content"), tf.readContents().getNormalizedText()); + } + + // different encoding to produce garbage, to make sure encoding is used + config.setSourceEncoding(StandardCharsets.UTF_16LE.name()); + try (TextFile tf = TextFile.dataSourceCompat(ds, config)) { + assertNotEquals(Chars.wrap("some content"), tf.readContents().getNormalizedText()); + } + } + @Test public void testNioFileWrite() throws IOException { Path file = makeTmpFile(StandardCharsets.UTF_8, "some content"); From 8a73559eb82f4d0414150a6f01f6bc2f5c119560 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 24 Apr 2022 18:24:03 +0200 Subject: [PATCH 126/180] Add tests for StringUtil --- .../net/sourceforge/pmd/util/StringUtil.java | 46 +++++++++++++++---- .../sourceforge/pmd/util/StringUtilTest.java | 18 ++++++++ 2 files changed, 54 insertions(+), 10 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/StringUtil.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/StringUtil.java index 4c82ffe662..8cc32d3a66 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/StringUtil.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/StringUtil.java @@ -278,16 +278,28 @@ public final class StringUtil { * leading characters can be removed to shift all the text in the strings to * the left without misaligning them. * + *
    + *
  • For each non-blank line (as defined by isBlank()), the leading white space characters are counted. + *
  • The leading white space characters on the last line are also counted even if blank. + *
+ * The min value is the smallest of these counts. + * + * * @throws NullPointerException If the parameter is null */ private static int maxCommonLeadingWhitespaceForAll(List lines) { - // the max *common* leading WS length is the min length of all leading WS int maxCommonWs = Integer.MAX_VALUE; for (int i = 0; i < lines.size(); i++) { CharSequence line = lines.get(i); // compute common prefix - if (!StringUtils.isAllBlank(line) || i == lines.size() - 1) { - maxCommonWs = Math.min(maxCommonWs, StringUtil.countLeadingWhitespace(line)); + if (!StringUtils.isBlank(line) || i == lines.size() - 1) { + maxCommonWs = Math.min(maxCommonWs, countLeadingWhitespace(line)); } } if (maxCommonWs == Integer.MAX_VALUE) { @@ -318,8 +330,9 @@ public final class StringUtil { } /** - * Trim common indentation in the lines of the string. - * Does not discard + * Trim common indentation in the lines of the string, like + * {@link #appendWithoutCommonPrefix(List, int, StringBuilder)}. + * */ public static StringBuilder trimIndent(Chars string) { List lines = string.lineStream().collect(Collectors.toList()); @@ -328,6 +341,16 @@ public final class StringUtil { return sb; } + /** + * Trim the common indentation of the lines and append them into + * the given StringBuilder, separating lines with \n. Trailing + * whitespace is removed on each line. Note that blank lines do + * not count towards computing the max common indentation, except + * the last one. + * + * @param lines List of lines to join + * @param sb Output StringBuilder + */ public static void trimIndentIntoStringBuilder(List lines, StringBuilder sb) { int prefixLength = maxCommonLeadingWhitespaceForAll(lines); appendWithoutCommonPrefix(lines, prefixLength, sb); @@ -335,18 +358,22 @@ public final class StringUtil { private static void appendWithoutCommonPrefix(List lines, int prefixLength, StringBuilder output) { for (int i = 0; i < lines.size(); i++) { + // For each non-blank line, min leading white space characters are removed, + // and any trailing white space characters are removed. + // Blank lines are replaced with the empty string. + Chars line = lines.get(i); // remove common whitespace prefix - if (!StringUtils.isAllBlank(line) && line.length() >= prefixLength) { + if (line.length() >= prefixLength && !StringUtils.isBlank(line)) { line = line.subSequence(prefixLength, line.length()); } + // trim trailing whitespace line = line.trimEnd(); + // append line.appendChars(output); boolean isLastLine = i == lines.size() - 1; - boolean isFirstLine = i == 0; - // todo is this &&? - if (!isLastLine || !isFirstLine && !StringUtils.isAllBlank(line)) { + if (!isLastLine) { output.append('\n'); // normalize line endings to LF } } @@ -403,7 +430,6 @@ public final class StringUtil { } - /** * Are the two String values the same. The Strings can be optionally trimmed * before checking. The Strings can be optionally compared ignoring case. diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/util/StringUtilTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/util/StringUtilTest.java index 65014ed765..16fdfa606e 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/util/StringUtilTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/util/StringUtilTest.java @@ -10,6 +10,8 @@ import static org.junit.Assert.assertEquals; import org.junit.Test; +import net.sourceforge.pmd.lang.document.Chars; + public class StringUtilTest { @Test @@ -82,6 +84,22 @@ public class StringUtilTest { assertThat(StringUtil.removeSurrounding("qqq", 'q'), equalTo("q")); } + @Test + public void testTrimIndent() { + assertTrimIndent(" \n b \n c", + "\nb\nc"); + + assertTrimIndent(" \nb \n c", + "\nb\n c"); + + assertTrimIndent(" \n b \n c\n ", + "\nb\nc\n"); + } + + private void assertTrimIndent(String input, String output) { + assertThat(StringUtil.trimIndent(Chars.wrap(input)).toString(), equalTo(output)); + } + @Test public void testElide() { assertThat(StringUtil.elide("abc", 2, ""), equalTo("ab")); From 4943dda381dc0631c733716db17dc23fd82c19b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 24 Apr 2022 19:18:23 +0200 Subject: [PATCH 127/180] Cleanup trimming logic --- .../pmd/lang/apex/ast/ApexTreeBuilder.java | 2 +- .../sourceforge/pmd/cpd/SimpleRenderer.java | 6 +- .../sourceforge/pmd/lang/document/Chars.java | 16 +++-- .../sourceforge/pmd/util/CollectionUtil.java | 11 +++ .../net/sourceforge/pmd/util/StringUtil.java | 71 +++++++++---------- .../sourceforge/pmd/util/StringUtilTest.java | 25 +++++++ .../pmd/lang/java/ast/ASTStringLiteral.java | 7 +- 7 files changed, 92 insertions(+), 46 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 c0a8b441c8..ca5e912e3c 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 @@ -436,7 +436,7 @@ final class ApexTreeBuilder extends AstVisitor { if (checkForCommentSuppression && commentText.startsWith("//")) { Chars trimmed = commentText.subSequence("//".length(), commentText.length()).trimStart(); if (trimmed.startsWith(suppressMarker)) { - Chars userMessage = trimmed.subSequence(suppressMarker.length(), trimmed.length()).trim(); + Chars userMessage = trimmed.subSequence(suppressMarker.length()).trim(); suppressMap.put(source.lineColumnAtOffset(startIdx).getLine(), userMessage.toString()); } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/SimpleRenderer.java b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/SimpleRenderer.java index 79e8cea468..5ce8ca7d48 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/SimpleRenderer.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/SimpleRenderer.java @@ -11,6 +11,7 @@ import java.util.Iterator; import net.sourceforge.pmd.PMD; import net.sourceforge.pmd.cpd.renderer.CPDRenderer; +import net.sourceforge.pmd.lang.document.Chars; import net.sourceforge.pmd.util.StringUtil; public class SimpleRenderer implements Renderer, CPDRenderer { @@ -49,8 +50,9 @@ public class SimpleRenderer implements Renderer, CPDRenderer { String source = match.getSourceCodeSlice(); if (trimLeadingWhitespace) { - for (String line : StringUtil.linesWithTrimIndent(source)) { - writer.append(line).append(PMD.EOL); + for (Chars line : StringUtil.linesWithTrimIndent(source)) { + line.writeFully(writer); + writer.append(PMD.EOL); } return; } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java index 0b002b22d7..c408bf90b5 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java @@ -363,6 +363,14 @@ public final class Chars implements CharSequence { return slice(start, end - start); } + /** + * Returns the subsequence that starts at the given offset and ends + * at the end of this string. Similar to {@link String#substring(int)}. + */ + public Chars subSequence(int start) { + return slice(start, len - start); + } + /** * Slice a region of text. * @@ -415,11 +423,11 @@ public final class Chars implements CharSequence { } private static void validateRangeWithAssert(int off, int len, int bound) { - assert len >= 0 && off >= 0 && (off + len) <= bound : invalidRange(off, len, bound); + assert len >= 0 && off >= 0 && off + len <= bound : invalidRange(off, len, bound); } private static void validateRange(int off, int len, int bound) { - if (len < 0 || off < 0 || (off + len) > bound) { + if (len < 0 || off < 0 || off + len > bound) { throw new IndexOutOfBoundsException(invalidRange(off, len, bound)); } } @@ -429,7 +437,7 @@ public final class Chars implements CharSequence { } @Override - public String toString() { + public @NonNull String toString() { // this already avoids the copy if start == 0 && len == str.length() return str.substring(start, start + len); } @@ -548,7 +556,7 @@ public final class Chars implements CharSequence { private final int max = start + len; @Override - public int read(char[] cbuf, int off, int len) { + public int read(char @NonNull [] cbuf, int off, int len) { if (len < 0 || off < 0 || off + len > cbuf.length) { throw new IndexOutOfBoundsException(); } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/CollectionUtil.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/CollectionUtil.java index e15cda62cd..82e191cc1a 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/CollectionUtil.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/CollectionUtil.java @@ -40,6 +40,7 @@ import org.pcollections.PSet; import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.internal.util.AssertionUtil; import net.sourceforge.pmd.internal.util.IteratorUtil; +import net.sourceforge.pmd.lang.document.Chars; /** * Generic collection and array-related utility functions for java.util types. @@ -635,6 +636,16 @@ public final class CollectionUtil { return sb; } + public static @NonNull StringBuilder joinCharsIntoStringBuilder(List lines, String delimiter) { + return joinOn( + new StringBuilder(), + lines, + (buf, line) -> line.appendChars(buf), + delimiter + ); + } + + /** * Merge the second map into the first. If some keys are in common, * merge them using the merge function, like {@link Map#merge(Object, Object, BiFunction)}. diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/StringUtil.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/StringUtil.java index 8cc32d3a66..8456b2ccfe 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/StringUtil.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/StringUtil.java @@ -279,8 +279,7 @@ public final class StringUtil { * the left without misaligning them. * *

Note: the spec is described in - * String#stripIndent + * String#stripIndent * * * The minimum indentation (min) is determined as follows: @@ -309,33 +308,36 @@ public final class StringUtil { return maxCommonWs; } + /** + * Returns a list of + */ + public static List linesWithTrimIndent(String source) { + List lines = Arrays.asList(source.split("\n")); + List result = lines.stream().map(Chars::wrap).collect(CollectionUtil.toMutableList()); + trimIndentInPlace(result); + return result; + } /** - * Trims off the leading characters off the strings up to the trimDepth - * specified. Returns the same strings if trimDepth = 0 - * - * @return String[] + * @param lines mutable list */ - private static String[] trimStartOn(String[] strings, int trimDepth) { - - if (trimDepth == 0) { - return strings; + public static void trimIndentInPlace(List lines) { + int trimDepth = maxCommonLeadingWhitespaceForAll(lines); + if (trimDepth > 0) { + lines.replaceAll(chars -> chars.length() >= trimDepth + ? chars.subSequence(trimDepth).trimEnd() + : chars.trimEnd()); } - - String[] results = new String[strings.length]; - for (int i = 0; i < strings.length; i++) { - results[i] = strings[i].substring(trimDepth); - } - return results; } /** * Trim common indentation in the lines of the string, like * {@link #appendWithoutCommonPrefix(List, int, StringBuilder)}. - * */ public static StringBuilder trimIndent(Chars string) { - List lines = string.lineStream().collect(Collectors.toList()); + List lines = string.lineStream().collect(CollectionUtil.toMutableList()); + trimIndentInPlace(lines); + StringBuilder sb = new StringBuilder(string.length()); trimIndentIntoStringBuilder(lines, sb); return sb; @@ -365,7 +367,7 @@ public final class StringUtil { Chars line = lines.get(i); // remove common whitespace prefix if (line.length() >= prefixLength && !StringUtils.isBlank(line)) { - line = line.subSequence(prefixLength, line.length()); + line = line.subSequence(prefixLength); } // trim trailing whitespace line = line.trimEnd(); @@ -398,17 +400,21 @@ public final class StringUtil { } } - int lastNonBlankLine = string.indexOf('\n', offsetOfLastNonBlankChar); - int firstNonBlankLine = string.lastIndexOf('\n', offsetOfFirstNonBlankChar); + // look backwards before the first non-blank char + int cutFromInclusive = string.lastIndexOf('\n', offsetOfFirstNonBlankChar); + // If firstNonBlankLineStart == -1, ie we're on the first line, + // we want to start at zero: then we add 1 to get 0 + // If firstNonBlankLineStart >= 0, then it's the index of the + // \n, we want to cut right after that, so we add 1. + cutFromInclusive += 1; - return string.subSequence( - minus1Default(firstNonBlankLine, 0), - minus1Default(lastNonBlankLine, string.length()) - ); - } + // look forwards after the last non-blank char + int cutUntilExclusive = string.indexOf('\n', offsetOfLastNonBlankChar); + if (cutUntilExclusive == StringUtils.INDEX_NOT_FOUND) { + cutUntilExclusive = string.length(); + } - private static int minus1Default(int i, int defaultValue) { - return i == -1 ? defaultValue : i; + return string.subSequence(cutFromInclusive, cutUntilExclusive); } @@ -420,15 +426,6 @@ public final class StringUtil { return count; } - public static String[] linesWithTrimIndent(String source) { - String[] lines = source.split("\n"); - int trimDepth = maxCommonLeadingWhitespaceForAll(Arrays.asList(lines)); - if (trimDepth > 0) { - lines = trimStartOn(lines, trimDepth); - } - return lines; - } - /** * Are the two String values the same. The Strings can be optionally trimmed diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/util/StringUtilTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/util/StringUtilTest.java index 16fdfa606e..76cb245169 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/util/StringUtilTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/util/StringUtilTest.java @@ -94,6 +94,7 @@ public class StringUtilTest { assertTrimIndent(" \n b \n c\n ", "\nb\nc\n"); + assertTrimIndent("", ""); } private void assertTrimIndent(String input, String output) { @@ -107,4 +108,28 @@ public class StringUtilTest { assertThat(StringUtil.elide("abc", 2, ".."), equalTo("..")); assertThat(StringUtil.elide("abc", 3, ".."), equalTo("abc")); } + + @Test + public void substringAfterLast() { + assertEquals("abc", StringUtil.substringAfterLast("a.abc", '.')); + assertEquals("abc", StringUtil.substringAfterLast("abc", '.')); + } + + @Test + public void trimBlankLines() { + assertTrimBlankLinesEquals(" \n \n abc \n \n de \n \n ", + " abc \n \n de "); + assertTrimBlankLinesEquals("", ""); + } + + private void assertTrimBlankLinesEquals(String input, String output) { + assertEquals( + Chars.wrap(output), + StringUtil.trimBlankLines(Chars.wrap(input)) + ); + } + + @Test + public void linesWithTrimIndent() { + } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStringLiteral.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStringLiteral.java index eb6cf5c377..004921b7da 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStringLiteral.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStringLiteral.java @@ -12,6 +12,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import net.sourceforge.pmd.lang.document.Chars; +import net.sourceforge.pmd.util.CollectionUtil; import net.sourceforge.pmd.util.StringUtil; /** @@ -83,8 +84,10 @@ public final class ASTStringLiteral extends AbstractLiteral implements ASTLitera static String determineTextBlockContent(Chars image) { List lines = getContentLines(image); - StringBuilder sb = new StringBuilder(image.length()); - StringUtil.trimIndentIntoStringBuilder(lines, sb); + // remove common prefix + StringUtil.trimIndentInPlace(lines); + // join with normalized end of line + StringBuilder sb = CollectionUtil.joinCharsIntoStringBuilder(lines, "\n"); interpretEscapeSequences(sb); return sb.toString(); } From 89545272af0bdaa0cc194d37f7163aa0e37c09dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 24 Apr 2022 19:33:21 +0200 Subject: [PATCH 128/180] Fix joinOn --- .../sourceforge/pmd/util/CollectionUtil.java | 2 +- .../pmd/util/CollectionUtilTest.java | 37 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 pmd-core/src/test/java/net/sourceforge/pmd/util/CollectionUtilTest.java diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/CollectionUtil.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/CollectionUtil.java index 82e191cc1a..3483a7f17d 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/CollectionUtil.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/CollectionUtil.java @@ -626,12 +626,12 @@ public final class CollectionUtil { String delimiter) { boolean first = true; for (T t : iterable) { - appendItem.accept(sb, t); if (first) { first = false; } else { sb.append(delimiter); } + appendItem.accept(sb, t); } return sb; } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/util/CollectionUtilTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/util/CollectionUtilTest.java new file mode 100644 index 0000000000..08234fe50c --- /dev/null +++ b/pmd-core/src/test/java/net/sourceforge/pmd/util/CollectionUtilTest.java @@ -0,0 +1,37 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.util; + +import static net.sourceforge.pmd.util.CollectionUtil.listOf; +import static org.junit.Assert.assertEquals; + +import java.util.Collections; +import java.util.List; + +import org.junit.Test; + +import net.sourceforge.pmd.lang.document.Chars; + +/** + * @author Clément Fournier + */ +public class CollectionUtilTest { + + @Test + public void testJoinOn() { + testJoinOn(listOf("a", "b", "c"), ".", + "a.b.c"); + testJoinOn(Collections.emptyList(), ".", + ""); + } + + private void testJoinOn(List toJoin, String delimiter, String expected) { + String actual = CollectionUtil.joinCharsIntoStringBuilder( + CollectionUtil.map(toJoin, Chars::wrap), + delimiter + ).toString(); + assertEquals(expected, actual); + } +} From e4627fb8411571aec24de0aed522a0b44ad5b54b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 24 Apr 2022 19:38:01 +0200 Subject: [PATCH 129/180] Move trimBlankLines --- .../sourceforge/pmd/lang/document/Chars.java | 37 +++++++++++++++++++ .../net/sourceforge/pmd/util/StringUtil.java | 36 ------------------ .../pmd/lang/document/CharsTest.java | 13 +++++++ .../sourceforge/pmd/util/StringUtilTest.java | 14 ------- .../pmd/testframework/RuleTst.java | 3 +- 5 files changed, 51 insertions(+), 52 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java index c408bf90b5..bb1cf4265c 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java @@ -295,6 +295,43 @@ public final class Chars implements CharSequence { return trimStart().trimEnd(); } + /** + * Remove trailing and leading blank lines. The resulting string + * does not end with a line terminator. + */ + public Chars trimBlankLines() { + int offsetOfFirstNonBlankChar = length(); + for (int i = 0; i < length(); i++) { + if (!Character.isWhitespace(charAt(i))) { + offsetOfFirstNonBlankChar = i; + break; + } + } + int offsetOfLastNonBlankChar = 0; + for (int i = length() - 1; i > offsetOfFirstNonBlankChar; i--) { + if (!Character.isWhitespace(charAt(i))) { + offsetOfLastNonBlankChar = i; + break; + } + } + + // look backwards before the first non-blank char + int cutFromInclusive = lastIndexOf('\n', offsetOfFirstNonBlankChar); + // If firstNonBlankLineStart == -1, ie we're on the first line, + // we want to start at zero: then we add 1 to get 0 + // If firstNonBlankLineStart >= 0, then it's the index of the + // \n, we want to cut right after that, so we add 1. + cutFromInclusive += 1; + + // look forwards after the last non-blank char + int cutUntilExclusive = indexOf('\n', offsetOfLastNonBlankChar); + if (cutUntilExclusive == StringUtils.INDEX_NOT_FOUND) { + cutUntilExclusive = length(); + } + + return subSequence(cutFromInclusive, cutUntilExclusive); + } + /** * Remove the suffix if it is present, otherwise returns this. */ diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/StringUtil.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/StringUtil.java index 8456b2ccfe..cc82caeb85 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/StringUtil.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/StringUtil.java @@ -381,42 +381,6 @@ public final class StringUtil { } } - /** - * Remove trailing and leading blank lines. - */ - public static Chars trimBlankLines(Chars string) { - int offsetOfFirstNonBlankChar = string.length(); - for (int i = 0; i < string.length(); i++) { - if (!Character.isWhitespace(string.charAt(i))) { - offsetOfFirstNonBlankChar = i; - break; - } - } - int offsetOfLastNonBlankChar = 0; - for (int i = string.length() - 1; i > offsetOfFirstNonBlankChar; i--) { - if (!Character.isWhitespace(string.charAt(i))) { - offsetOfLastNonBlankChar = i; - break; - } - } - - // look backwards before the first non-blank char - int cutFromInclusive = string.lastIndexOf('\n', offsetOfFirstNonBlankChar); - // If firstNonBlankLineStart == -1, ie we're on the first line, - // we want to start at zero: then we add 1 to get 0 - // If firstNonBlankLineStart >= 0, then it's the index of the - // \n, we want to cut right after that, so we add 1. - cutFromInclusive += 1; - - // look forwards after the last non-blank char - int cutUntilExclusive = string.indexOf('\n', offsetOfLastNonBlankChar); - if (cutUntilExclusive == StringUtils.INDEX_NOT_FOUND) { - cutUntilExclusive = string.length(); - } - - return string.subSequence(cutFromInclusive, cutUntilExclusive); - } - private static int countLeadingWhitespace(CharSequence s) { int count = 0; diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/CharsTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/CharsTest.java index 7b193fcb29..e19a5a5366 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/CharsTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/CharsTest.java @@ -310,4 +310,17 @@ public class CharsTest { assertThrows(IndexOutOfBoundsException.class, () -> chars.substring(0, 6)); } + + @Test + public void testTrimBlankLines() { + assertTrimBlankLinesEquals(" \n \n abc \n \n de \n \n ", + " abc \n \n de "); + assertTrimBlankLinesEquals("", ""); + } + + private void assertTrimBlankLinesEquals(String input, String expected) { + Chars actual = Chars.wrap(input).trimBlankLines(); + assertEquals(Chars.wrap(expected), actual); + } + } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/util/StringUtilTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/util/StringUtilTest.java index 76cb245169..8f9abce19d 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/util/StringUtilTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/util/StringUtilTest.java @@ -115,20 +115,6 @@ public class StringUtilTest { assertEquals("abc", StringUtil.substringAfterLast("abc", '.')); } - @Test - public void trimBlankLines() { - assertTrimBlankLinesEquals(" \n \n abc \n \n de \n \n ", - " abc \n \n de "); - assertTrimBlankLinesEquals("", ""); - } - - private void assertTrimBlankLinesEquals(String input, String output) { - assertEquals( - Chars.wrap(output), - StringUtil.trimBlankLines(Chars.wrap(input)) - ); - } - @Test public void linesWithTrimIndent() { } diff --git a/pmd-test/src/main/java/net/sourceforge/pmd/testframework/RuleTst.java b/pmd-test/src/main/java/net/sourceforge/pmd/testframework/RuleTst.java index ff358b038b..d6deafb510 100644 --- a/pmd-test/src/main/java/net/sourceforge/pmd/testframework/RuleTst.java +++ b/pmd-test/src/main/java/net/sourceforge/pmd/testframework/RuleTst.java @@ -50,7 +50,6 @@ import net.sourceforge.pmd.processor.AbstractPMDProcessor; import net.sourceforge.pmd.properties.PropertyDescriptor; import net.sourceforge.pmd.renderers.TextRenderer; import net.sourceforge.pmd.reporting.GlobalAnalysisListener; -import net.sourceforge.pmd.util.StringUtil; /** * Advanced methods for test cases @@ -486,7 +485,7 @@ public abstract class RuleTst { throw new RuntimeException("No matching code fragment found for coderef"); } } - code = StringUtil.trimBlankLines(Chars.wrap(code)).toString(); + code = Chars.wrap(code).trimBlankLines().toString(); String description = getNodeValue(testCode, "description", true); int expectedProblems = Integer.parseInt(getNodeValue(testCode, "expected-problems", true).trim()); From 871fcc3cedd77943c721ac26935ec62219f8f988 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 24 Apr 2022 19:42:01 +0200 Subject: [PATCH 130/180] Finish cleaning up trimming logic --- .../net/sourceforge/pmd/util/StringUtil.java | 61 ++++--------------- .../sourceforge/pmd/util/StringUtilTest.java | 6 +- .../pmd/lang/java/ast/ASTStringLiteral.java | 1 + 3 files changed, 15 insertions(+), 53 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/StringUtil.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/StringUtil.java index cc82caeb85..61e577c175 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/StringUtil.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/StringUtil.java @@ -319,66 +319,29 @@ public final class StringUtil { } /** + * Trim the common indentation of each line in place in the input list. + * Trailing whitespace is removed on each line. Note that blank lines do + * not count towards computing the max common indentation, except + * the last one. + * * @param lines mutable list */ public static void trimIndentInPlace(List lines) { int trimDepth = maxCommonLeadingWhitespaceForAll(lines); - if (trimDepth > 0) { - lines.replaceAll(chars -> chars.length() >= trimDepth - ? chars.subSequence(trimDepth).trimEnd() - : chars.trimEnd()); - } + lines.replaceAll(chars -> chars.length() >= trimDepth + ? chars.subSequence(trimDepth).trimEnd() + : chars.trimEnd()); } /** - * Trim common indentation in the lines of the string, like - * {@link #appendWithoutCommonPrefix(List, int, StringBuilder)}. + * Trim common indentation in the lines of the string. Like + * {@link #trimIndentInPlace(List)} called with the list of lines + * and joined with {@code \n}. */ public static StringBuilder trimIndent(Chars string) { List lines = string.lineStream().collect(CollectionUtil.toMutableList()); trimIndentInPlace(lines); - - StringBuilder sb = new StringBuilder(string.length()); - trimIndentIntoStringBuilder(lines, sb); - return sb; - } - - /** - * Trim the common indentation of the lines and append them into - * the given StringBuilder, separating lines with \n. Trailing - * whitespace is removed on each line. Note that blank lines do - * not count towards computing the max common indentation, except - * the last one. - * - * @param lines List of lines to join - * @param sb Output StringBuilder - */ - public static void trimIndentIntoStringBuilder(List lines, StringBuilder sb) { - int prefixLength = maxCommonLeadingWhitespaceForAll(lines); - appendWithoutCommonPrefix(lines, prefixLength, sb); - } - - private static void appendWithoutCommonPrefix(List lines, int prefixLength, StringBuilder output) { - for (int i = 0; i < lines.size(); i++) { - // For each non-blank line, min leading white space characters are removed, - // and any trailing white space characters are removed. - // Blank lines are replaced with the empty string. - - Chars line = lines.get(i); - // remove common whitespace prefix - if (line.length() >= prefixLength && !StringUtils.isBlank(line)) { - line = line.subSequence(prefixLength); - } - // trim trailing whitespace - line = line.trimEnd(); - // append - line.appendChars(output); - - boolean isLastLine = i == lines.size() - 1; - if (!isLastLine) { - output.append('\n'); // normalize line endings to LF - } - } + return CollectionUtil.joinCharsIntoStringBuilder(lines, "\n"); } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/util/StringUtilTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/util/StringUtilTest.java index 8f9abce19d..45c008a6b5 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/util/StringUtilTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/util/StringUtilTest.java @@ -98,7 +98,8 @@ public class StringUtilTest { } private void assertTrimIndent(String input, String output) { - assertThat(StringUtil.trimIndent(Chars.wrap(input)).toString(), equalTo(output)); + String actual = StringUtil.trimIndent(Chars.wrap(input)).toString(); + assertThat(actual, equalTo(output)); } @Test @@ -115,7 +116,4 @@ public class StringUtilTest { assertEquals("abc", StringUtil.substringAfterLast("abc", '.')); } - @Test - public void linesWithTrimIndent() { - } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStringLiteral.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStringLiteral.java index 004921b7da..be73eccec1 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStringLiteral.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStringLiteral.java @@ -88,6 +88,7 @@ public final class ASTStringLiteral extends AbstractLiteral implements ASTLitera StringUtil.trimIndentInPlace(lines); // join with normalized end of line StringBuilder sb = CollectionUtil.joinCharsIntoStringBuilder(lines, "\n"); + // interpret escape sequences interpretEscapeSequences(sb); return sb.toString(); } From 0b44c7d247729c509768876689f7db7874700170 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 24 Apr 2022 19:54:03 +0200 Subject: [PATCH 131/180] Fix test in pmd-java RuleTst doesn't trim messages now --- .../java/rule/codestyle/xml/UnnecessaryFullyQualifiedName.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UnnecessaryFullyQualifiedName.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UnnecessaryFullyQualifiedName.xml index e59544b468..85f6c7871c 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UnnecessaryFullyQualifiedName.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UnnecessaryFullyQualifiedName.xml @@ -852,7 +852,7 @@ class Assert { 1 4 - Unnecessary qualifier 'java.lang': 'Math' is already in scope because it is declared in java.lang + Unnecessary qualifier 'java.lang': 'Math' is already in scope because it is declared in java.lang Date: Mon, 25 Apr 2022 02:25:18 +0800 Subject: [PATCH 132/180] Update pmd-java/src/main/resources/category/java/design.xml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Clément Fournier --- pmd-java/src/main/resources/category/java/design.xml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pmd-java/src/main/resources/category/java/design.xml b/pmd-java/src/main/resources/category/java/design.xml index 1835882366..58159b565b 100644 --- a/pmd-java/src/main/resources/category/java/design.xml +++ b/pmd-java/src/main/resources/category/java/design.xml @@ -1311,11 +1311,7 @@ or From 38d3c091d0007c075f02e23081f21e687ba07400 Mon Sep 17 00:00:00 2001 From: LaLucid <55886143+VoidxHoshi@users.noreply.github.com> Date: Mon, 25 Apr 2022 02:27:26 +0800 Subject: [PATCH 133/180] Update pmd-java/src/main/resources/category/java/design.xml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Clément Fournier --- .../src/main/resources/category/java/design.xml | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/pmd-java/src/main/resources/category/java/design.xml b/pmd-java/src/main/resources/category/java/design.xml index 58159b565b..5b4d7bbc99 100644 --- a/pmd-java/src/main/resources/category/java/design.xml +++ b/pmd-java/src/main/resources/category/java/design.xml @@ -1292,17 +1292,11 @@ Look for ternary operators with the form `condition ? literalBoolean : foo` or `condition ? foo : literalBoolean` or `condition ? literalBoolean1 : literalBoolean2`. -These expressions can be simplified respectively to -`condition || foo` when the literalBoolean is true -`!condition && foo` when the literalBoolean is false -or -`!condition || foo` when the literalBoolean is true -`condition && foo` when the literalBoolean is false -or -`true` when the literalBoolean are both true -`false` when the literalBoolean are both false -`condition` when the literalBoolean1 is true and the literalBoolean2 is false -`!condition` when the literalBoolean1 is false and the literalBoolean2 is true +These expressions can be simplified as follows: +* `condition ? true : expr` simplifies to `condition || expr` +* `condition ? false : expr` simplifies to `!condition && expr` +* `condition ? expr : true` simplifies to `!condition || expr` +* `condition ? expr : false` simplifies to `condition && expr` ]]> 3 From 56cc9fc1638bf8ec31dc40e1f177837d2185dce9 Mon Sep 17 00:00:00 2001 From: LaLucid <55886143+VoidxHoshi@users.noreply.github.com> Date: Mon, 25 Apr 2022 02:35:34 +0800 Subject: [PATCH 134/180] make the description simple --- pmd-java/src/main/resources/category/java/design.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pmd-java/src/main/resources/category/java/design.xml b/pmd-java/src/main/resources/category/java/design.xml index 5b4d7bbc99..9c90dabf44 100644 --- a/pmd-java/src/main/resources/category/java/design.xml +++ b/pmd-java/src/main/resources/category/java/design.xml @@ -1289,8 +1289,7 @@ public void foo() throws Exception { Date: Mon, 25 Apr 2022 03:31:19 +0800 Subject: [PATCH 135/180] modify the SimplifiedTernary test --- .../pmd/lang/java/rule/design/xml/SimplifiedTernary.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/SimplifiedTernary.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/SimplifiedTernary.xml index 2002135780..1a01776aeb 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/SimplifiedTernary.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/SimplifiedTernary.xml @@ -53,12 +53,12 @@ public class Foo { - condition ? true : false - 0 + #3603 condition ? true : false + 1 From 1f9c7c57654648df6d25fdee54b48f4a5f58c69a Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sun, 24 Apr 2022 22:26:46 +0200 Subject: [PATCH 136/180] [test] Print Test Method Name for failed rule tests This helps to select just this failed test to rerun it within the IDE. Also replace parenthesis in the test case description. --- .../sourceforge/pmd/testframework/PMDTestRunner.java | 8 ++++++++ .../sourceforge/pmd/testframework/RuleTestRunner.java | 5 +---- .../net/sourceforge/pmd/testframework/RuleTst.java | 1 + .../sourceforge/pmd/testframework/TestDescriptor.java | 11 +++++++++++ 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/pmd-test/src/main/java/net/sourceforge/pmd/testframework/PMDTestRunner.java b/pmd-test/src/main/java/net/sourceforge/pmd/testframework/PMDTestRunner.java index a0e05007bf..4511625989 100644 --- a/pmd-test/src/main/java/net/sourceforge/pmd/testframework/PMDTestRunner.java +++ b/pmd-test/src/main/java/net/sourceforge/pmd/testframework/PMDTestRunner.java @@ -42,6 +42,8 @@ public class PMDTestRunner extends Runner implements Filterable, Sortable { private final RuleTestRunner ruleTests; private final ParentRunner unitTests; + private final Description description; + public PMDTestRunner(final Class klass) throws InitializationError { this.klass = klass; ruleTests = new RuleTestRunner(klass); @@ -51,6 +53,8 @@ public class PMDTestRunner extends Runner implements Filterable, Sortable { } else { unitTests = new EmptyRunner(klass); } + + this.description = createDescription(); } @Override @@ -76,6 +80,10 @@ public class PMDTestRunner extends Runner implements Filterable, Sortable { @Override public Description getDescription() { + return description; + } + + private Description createDescription() { Description description = Description.createSuiteDescription(klass); description.addChild(createChildrenDescriptions(ruleTests, "Rule Tests")); if (ruleTests.hasUnitTests()) { diff --git a/pmd-test/src/main/java/net/sourceforge/pmd/testframework/RuleTestRunner.java b/pmd-test/src/main/java/net/sourceforge/pmd/testframework/RuleTestRunner.java index 7420567b0b..7007053ffc 100644 --- a/pmd-test/src/main/java/net/sourceforge/pmd/testframework/RuleTestRunner.java +++ b/pmd-test/src/main/java/net/sourceforge/pmd/testframework/RuleTestRunner.java @@ -47,10 +47,7 @@ public class RuleTestRunner extends ParentRunner { protected Description describeChild(TestDescriptor testCase) { Description description = testDescriptions.get(testCase); if (description == null) { - description = Description.createTestDescription(getTestClass().getJavaClass(), - testCase.getRule().getName() + "::" - + testCase.getNumberInDocument() + " " - + testCase.getDescription().replaceAll("\n|\r", " ")); + description = Description.createTestDescription(getTestClass().getJavaClass().getName(), testCase.getTestMethodName()); testDescriptions.putIfAbsent(testCase, description); } return description; diff --git a/pmd-test/src/main/java/net/sourceforge/pmd/testframework/RuleTst.java b/pmd-test/src/main/java/net/sourceforge/pmd/testframework/RuleTst.java index 06c7fa9d38..244ff01fd1 100644 --- a/pmd-test/src/main/java/net/sourceforge/pmd/testframework/RuleTst.java +++ b/pmd-test/src/main/java/net/sourceforge/pmd/testframework/RuleTst.java @@ -239,6 +239,7 @@ public abstract class RuleTst { + " problem(s) found."); System.out.println(" -> Expected messages: " + test.getExpectedMessages()); System.out.println(" -> Expected line numbers: " + test.getExpectedLineNumbers()); + System.out.println("Test Method Name: " + test.getTestMethodName()); System.out.println(); TextRenderer renderer = new TextRenderer(); renderer.setWriter(new StringWriter()); diff --git a/pmd-test/src/main/java/net/sourceforge/pmd/testframework/TestDescriptor.java b/pmd-test/src/main/java/net/sourceforge/pmd/testframework/TestDescriptor.java index dcb4ba6fd4..894226a883 100644 --- a/pmd-test/src/main/java/net/sourceforge/pmd/testframework/TestDescriptor.java +++ b/pmd-test/src/main/java/net/sourceforge/pmd/testframework/TestDescriptor.java @@ -148,4 +148,15 @@ public class TestDescriptor { public boolean isUseAuxClasspath() { return useAuxClasspath; } + + public String getTestMethodName() { + String methodName = getRule().getName() + "_" + + getNumberInDocument() + + "_" + + getDescription() + .replaceAll("\n|\r", "_") + .replaceAll("[\\(\\)]|\\s", "_"); + + return methodName; + } } From 6ec5fe1073dd91abfded114ff8f194537c9693a5 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sun, 24 Apr 2022 22:44:05 +0200 Subject: [PATCH 137/180] Fix pmd --- .../net/sourceforge/pmd/testframework/TestDescriptor.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pmd-test/src/main/java/net/sourceforge/pmd/testframework/TestDescriptor.java b/pmd-test/src/main/java/net/sourceforge/pmd/testframework/TestDescriptor.java index 894226a883..706f5f154b 100644 --- a/pmd-test/src/main/java/net/sourceforge/pmd/testframework/TestDescriptor.java +++ b/pmd-test/src/main/java/net/sourceforge/pmd/testframework/TestDescriptor.java @@ -150,13 +150,11 @@ public class TestDescriptor { } public String getTestMethodName() { - String methodName = getRule().getName() + "_" + return getRule().getName() + "_" + getNumberInDocument() + "_" + getDescription() .replaceAll("\n|\r", "_") - .replaceAll("[\\(\\)]|\\s", "_"); - - return methodName; + .replaceAll("[\\.\\(\\)]|\\s", "_"); } } From 3841e7d0c9bfcefda8ccdd1f5043bd65114c3c68 Mon Sep 17 00:00:00 2001 From: LaLucid <55886143+VoidxHoshi@users.noreply.github.com> Date: Mon, 25 Apr 2022 06:50:56 +0800 Subject: [PATCH 138/180] Revert the original XPath --- pmd-java/src/main/resources/category/java/design.xml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pmd-java/src/main/resources/category/java/design.xml b/pmd-java/src/main/resources/category/java/design.xml index 9c90dabf44..7f81f291dc 100644 --- a/pmd-java/src/main/resources/category/java/design.xml +++ b/pmd-java/src/main/resources/category/java/design.xml @@ -1304,7 +1304,11 @@ These expressions can be simplified as follows: From 6d83eda6be37c298dda825a86e9d21889084a9f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 26 Apr 2022 00:59:48 +0200 Subject: [PATCH 139/180] Fix sort on unmodifiable list --- pmd-core/src/main/java/net/sourceforge/pmd/PMD.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/PMD.java b/pmd-core/src/main/java/net/sourceforge/pmd/PMD.java index fc87782685..8bd518f276 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/PMD.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/PMD.java @@ -14,6 +14,7 @@ import java.util.Comparator; import java.util.List; import java.util.Map.Entry; import java.util.Objects; +import java.util.stream.Collectors; import org.checkerframework.checker.nullness.qual.NonNull; import org.slf4j.Logger; @@ -34,7 +35,6 @@ import net.sourceforge.pmd.lang.document.TextFile; import net.sourceforge.pmd.renderers.Renderer; import net.sourceforge.pmd.reporting.ReportStats; import net.sourceforge.pmd.reporting.ReportStatsListener; -import net.sourceforge.pmd.util.CollectionUtil; import net.sourceforge.pmd.util.datasource.DataSource; import net.sourceforge.pmd.util.log.MessageReporter; import net.sourceforge.pmd.util.log.internal.SimpleMessageReporter; @@ -140,9 +140,11 @@ public final class PMD { pmd.addRenderers(renderers); @SuppressWarnings("PMD.CloseResource") GlobalReportBuilderListener reportBuilder = new GlobalReportBuilderListener(); - List textFiles = CollectionUtil.map(files, ds -> TextFile.dataSourceCompat(ds, configuration)); - textFiles.sort(Comparator.comparing(TextFile::getPathId)); - pmd.performAnalysisImpl(listOf(reportBuilder), textFiles); + List sortedFiles = files.stream() + .map(ds -> TextFile.dataSourceCompat(ds, configuration)) + .sorted(Comparator.comparing(TextFile::getPathId)) + .collect(Collectors.toList()); + pmd.performAnalysisImpl(listOf(reportBuilder), sortedFiles); return reportBuilder.getResult(); } } From 5d07ce4bb8919f728dbf77302307cc6e5521f367 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 26 Apr 2022 01:00:06 +0200 Subject: [PATCH 140/180] Deprecate DataSource Update comments --- .../main/java/net/sourceforge/pmd/PMD.java | 1 - .../sourceforge/pmd/cache/AnalysisCache.java | 7 +++---- .../pmd/lang/document/TextDocument.java | 19 ------------------- .../pmd/util/datasource/DataSource.java | 5 +++++ 4 files changed, 8 insertions(+), 24 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/PMD.java b/pmd-core/src/main/java/net/sourceforge/pmd/PMD.java index 8bd518f276..4dd8f5f2b7 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/PMD.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/PMD.java @@ -126,7 +126,6 @@ public final class PMD { * @return Report in which violations are accumulated * * @throws Exception If there was a problem when opening or closing the renderers - * * @deprecated Use {@link PmdAnalysis} */ @Deprecated diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cache/AnalysisCache.java b/pmd-core/src/main/java/net/sourceforge/pmd/cache/AnalysisCache.java index 274c740c1f..675df7b7f8 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/cache/AnalysisCache.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/cache/AnalysisCache.java @@ -4,7 +4,6 @@ package net.sourceforge.pmd.cache; -import java.io.File; import java.io.IOException; import java.util.List; @@ -12,9 +11,9 @@ import net.sourceforge.pmd.RuleSets; import net.sourceforge.pmd.RuleViolation; import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.document.TextDocument; +import net.sourceforge.pmd.lang.document.TextFile; import net.sourceforge.pmd.reporting.FileAnalysisListener; import net.sourceforge.pmd.reporting.GlobalAnalysisListener; -import net.sourceforge.pmd.util.datasource.DataSource; /** * An analysis cache for incremental analysis. @@ -68,8 +67,8 @@ public interface AnalysisCache { void checkValidity(RuleSets ruleSets, ClassLoader auxclassPathClassLoader); /** - * Returns a listener that will be used like in {@link GlobalAnalysisListener#startFileAnalysis(DataSource)}. - * This should record violations, and call {@link #analysisFailed(File)} + * Returns a listener that will be used like in {@link GlobalAnalysisListener#startFileAnalysis(TextFile)}. + * This should record violations, and call {@link #analysisFailed(TextDocument)} * upon error. */ FileAnalysisListener startFileAnalysis(TextDocument file); diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextDocument.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextDocument.java index 6bb71432c8..6bfc817b09 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextDocument.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextDocument.java @@ -77,25 +77,6 @@ public interface TextDocument extends Closeable { // todo text edition (there are some reverted commits in the branch // with part of this, including a lot of tests) - /* - Summary of different coordinate systems: - Coordinate system: Line/column Offset - ============================================================== - Position: TextPos2d int >= 0 - Range: TextRange2d TextRegion - - (FileLocation is similar to TextRange2d in terms of position info) - - Conversions: - line/column -> offset: offsetAtLineColumn - offset -> line/column: lineColumnAtOffset - Range conversions: - TextRegion -> TextRange2d: toRegion - TextRange2d -> TextRegion: toRange2d - - TextRegion -> FileLocation: toLocation - TextRange2d -> FileLocation: toLocation - */ /** * Returns the language version that should be used to parse this file. diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/datasource/DataSource.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/datasource/DataSource.java index 2f0085bceb..a215b7aea8 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/datasource/DataSource.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/datasource/DataSource.java @@ -9,11 +9,16 @@ import java.io.IOException; import java.io.InputStream; import java.io.StringReader; +import net.sourceforge.pmd.lang.document.TextFile; + /** * Represents a source file to be analyzed. Different implementations can get * the source file from different places: the filesystem, a zip or jar file, * etc. + * + * @deprecated Use {@link TextFile} */ +@Deprecated public interface DataSource extends Closeable { /** From e951d6df8f976a23f0c840831109f53ee9366b84 Mon Sep 17 00:00:00 2001 From: LaLucid <55886143+VoidxHoshi@users.noreply.github.com> Date: Wed, 27 Apr 2022 04:07:02 +0800 Subject: [PATCH 141/180] Use a more clear XPath form to replace the former --- pmd-java/src/main/resources/category/java/design.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pmd-java/src/main/resources/category/java/design.xml b/pmd-java/src/main/resources/category/java/design.xml index 7f81f291dc..a5446a8304 100644 --- a/pmd-java/src/main/resources/category/java/design.xml +++ b/pmd-java/src/main/resources/category/java/design.xml @@ -1304,11 +1304,11 @@ These expressions can be simplified as follows: From f29770f968e0271891b3908682ab70107c1a244b Mon Sep 17 00:00:00 2001 From: LaLucid <55886143+VoidxHoshi@users.noreply.github.com> Date: Wed, 27 Apr 2022 05:47:07 +0800 Subject: [PATCH 142/180] Use a more clear XPath form MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Clément Fournier --- pmd-java/src/main/resources/category/java/design.xml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/pmd-java/src/main/resources/category/java/design.xml b/pmd-java/src/main/resources/category/java/design.xml index a5446a8304..b285179dba 100644 --- a/pmd-java/src/main/resources/category/java/design.xml +++ b/pmd-java/src/main/resources/category/java/design.xml @@ -1304,11 +1304,9 @@ These expressions can be simplified as follows: From 45e4ec9e983d327f37e05730c5dea66ee40ec21c Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 28 Apr 2022 09:58:59 +0200 Subject: [PATCH 143/180] [plsql] Migrate ExecuteImmediateBulkCollectTest to BaseTreeDumpTest --- pmd-plsql/etc/grammar/PldocAST.jjt | 3 + .../ast/ExecuteImmediateBulkCollectTest.java | 27 ++- .../ast/ExecuteImmediateBulkCollect1.pls | 6 +- .../ast/ExecuteImmediateBulkCollect1.txt | 74 ++++++ .../ast/ExecuteImmediateBulkCollect2.pls | 6 +- .../ast/ExecuteImmediateBulkCollect2.txt | 221 ++++++++++++++++++ .../ast/ExecuteImmediateBulkCollect3.pls | 6 +- .../ast/ExecuteImmediateBulkCollect3.txt | 160 +++++++++++++ .../pmd/lang/plsql/ast/ParenthesisGroup0.pls | 4 + .../pmd/lang/plsql/ast/ParenthesisGroup0.txt | 6 +- .../pmd/lang/plsql/ast/ParenthesisGroup1.pls | 4 + .../pmd/lang/plsql/ast/ParenthesisGroup1.txt | 6 +- .../pmd/lang/plsql/ast/ParenthesisGroup2.pls | 4 + .../pmd/lang/plsql/ast/ParenthesisGroup2.txt | 6 +- 14 files changed, 518 insertions(+), 15 deletions(-) create mode 100644 pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect1.txt create mode 100644 pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect2.txt create mode 100644 pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect3.txt diff --git a/pmd-plsql/etc/grammar/PldocAST.jjt b/pmd-plsql/etc/grammar/PldocAST.jjt index 1ec8e28725..7013c9dd44 100644 --- a/pmd-plsql/etc/grammar/PldocAST.jjt +++ b/pmd-plsql/etc/grammar/PldocAST.jjt @@ -2814,6 +2814,9 @@ ASTFetchStatement FetchStatement() : { return jjtThis ; } } +/** + * Execute Immediate: https://docs.oracle.com/en/database/oracle/oracle-database/18/lnpls/EXECUTE-IMMEDIATE-statement.html#GUID-C3245A95-B85B-4280-A01F-12307B108DC8 + */ ASTEmbeddedSqlStatement EmbeddedSqlStatement() : {} { diff --git a/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollectTest.java b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollectTest.java index 8def0bb7af..63982ea168 100644 --- a/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollectTest.java +++ b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollectTest.java @@ -4,27 +4,36 @@ package net.sourceforge.pmd.lang.plsql.ast; -import org.junit.Assert; import org.junit.Test; -import net.sourceforge.pmd.lang.plsql.AbstractPLSQLParserTst; +import net.sourceforge.pmd.lang.ast.test.BaseParsingHelper; +import net.sourceforge.pmd.lang.ast.test.BaseTreeDumpTest; +import net.sourceforge.pmd.lang.ast.test.RelevantAttributePrinter; +import net.sourceforge.pmd.lang.plsql.PlsqlParsingHelper; + +public class ExecuteImmediateBulkCollectTest extends BaseTreeDumpTest { + + public ExecuteImmediateBulkCollectTest() { + super(new RelevantAttributePrinter(), ".pls"); + } + + @Override + public BaseParsingHelper getParser() { + return PlsqlParsingHelper.WITH_PROCESSING.withResourceContext(getClass()); + } -public class ExecuteImmediateBulkCollectTest extends AbstractPLSQLParserTst { @Test public void testExecuteImmediateBulkCollect1() { - ASTInput input = plsql.parseResource("ExecuteImmediateBulkCollect1.pls"); - Assert.assertNotNull(input); + doTest("ExecuteImmediateBulkCollect1"); } @Test public void testExecuteImmediateBulkCollect2() { - ASTInput input = plsql.parseResource("ExecuteImmediateBulkCollect2.pls"); - Assert.assertNotNull(input); + doTest("ExecuteImmediateBulkCollect2"); } @Test public void testExecuteImmediateBulkCollect3() { - ASTInput input = plsql.parseResource("ExecuteImmediateBulkCollect3.pls"); - Assert.assertNotNull(input); + doTest("ExecuteImmediateBulkCollect3"); } } diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect1.pls b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect1.pls index f4951287e3..cbb83cd788 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect1.pls +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect1.pls @@ -1,3 +1,7 @@ +-- +-- BSD-style license; for more info see http://pmd.sourceforge.net/license.html +-- + CREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS -- TYPE t_data IS TABLE OF dual%ROWTYPE INDEX BY BINARY_INTEGER; @@ -12,4 +16,4 @@ BEGIN EXECUTE IMMEDIATE l_sql BULK COLLECT INTO l_data; -- -END EXAMPLE_PROCEDURE; \ No newline at end of file +END EXAMPLE_PROCEDURE; diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect1.txt b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect1.txt new file mode 100644 index 0000000000..6c18018e50 --- /dev/null +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect1.txt @@ -0,0 +1,74 @@ ++- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0, @Sourcecode = "-- +-- BSD-style license; for more info see http://pmd.sourceforge.net/license.html +-- + +CREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS + -- + TYPE t_data IS TABLE OF dual%ROWTYPE INDEX BY BINARY_INTEGER; + -- + l_data t_data; + l_sql VARCHAR2(500); + -- +BEGIN + -- + l_sql := 'SELECT * FROM DUAL'; + -- + EXECUTE IMMEDIATE l_sql BULK COLLECT + INTO l_data; + -- +END EXAMPLE_PROCEDURE; +"] + +- Global[@CanonicalImage = null] + +- ProgramUnit[@CanonicalImage = null, @MethodName = "EXAMPLE_PROCEDURE", @Name = "EXAMPLE_PROCEDURE", @ObjectName = null] + +- MethodDeclarator[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE", @ParameterCount = 1] + | +- ObjectNameDeclaration[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE"] + | +- ID[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE"] + +- DeclarativeSection[@CanonicalImage = null] + | +- DeclarativeUnit[@CanonicalImage = null] + | | +- SubTypeDefinition[@CanonicalImage = "T_DATA", @Image = "t_data"] + | | +- QualifiedID[@CanonicalImage = "T_DATA", @Image = "t_data"] + | | +- Datatype[@CanonicalImage = "DUAL%ROWTYPE", @Image = "dual%ROWTYPE", @TypeImage = "dual%ROWTYPE"] + | | | +- QualifiedName[@CanonicalImage = "DUAL", @Image = "dual"] + | | | +- UnqualifiedID[@CanonicalImage = "DUAL", @Image = "dual"] + | | +- Datatype[@CanonicalImage = "BINARY_INTEGER", @Image = "BINARY_INTEGER", @TypeImage = "BINARY_INTEGER"] + | | +- ScalarDataTypeName[@CanonicalImage = "BINARY_INTEGER", @Image = "BINARY_INTEGER"] + | +- DeclarativeUnit[@CanonicalImage = null] + | | +- VariableOrConstantDeclaration[@CanonicalImage = null] + | | +- VariableOrConstantDeclarator[@CanonicalImage = "L_DATA T_DATA", @Image = "l_data t_data"] + | | +- VariableOrConstantDeclaratorId[@Array = false, @ArrayDepth = 0, @CanonicalImage = "L_DATA", @Image = "l_data"] + | | | +- ID[@CanonicalImage = "L_DATA", @Image = "l_data"] + | | +- Datatype[@CanonicalImage = "T_DATA", @Image = "t_data", @TypeImage = "t_data"] + | | +- QualifiedName[@CanonicalImage = "T_DATA", @Image = "t_data"] + | | +- UnqualifiedID[@CanonicalImage = "T_DATA", @Image = "t_data"] + | +- DeclarativeUnit[@CanonicalImage = null] + | +- VariableOrConstantDeclaration[@CanonicalImage = null] + | +- VariableOrConstantDeclarator[@CanonicalImage = "L_SQL VARCHAR2(500)", @Image = "l_sql VARCHAR2(500)"] + | +- VariableOrConstantDeclaratorId[@Array = false, @ArrayDepth = 0, @CanonicalImage = "L_SQL", @Image = "l_sql"] + | | +- ID[@CanonicalImage = "L_SQL", @Image = "l_sql"] + | +- Datatype[@CanonicalImage = "VARCHAR2(500)", @Image = "VARCHAR2(500)", @TypeImage = "VARCHAR2(500)"] + | +- ScalarDataTypeName[@CanonicalImage = "VARCHAR2(500)", @Image = "VARCHAR2(500)"] + | +- NumericLiteral[@CanonicalImage = "500", @Image = "500"] + +- Statement[@CanonicalImage = null] + | +- UnlabelledStatement[@CanonicalImage = null] + | +- Expression[@CanonicalImage = "L_SQL := 'SELECT * FROM DUAL'", @Image = "l_sql := 'SELECT * FROM DUAL'"] + | +- Assignment[@CanonicalImage = "L_SQL := 'SELECT * FROM DUAL'", @Image = "l_sql := 'SELECT * FROM DUAL'"] + | +- PrimaryPrefix[@CanonicalImage = "L_SQL", @Image = "l_sql", @SelfModifier = false] + | | +- SimpleExpression[@CanonicalImage = "L_SQL", @Image = "l_sql"] + | | +- Column[@CanonicalImage = "L_SQL", @Image = "l_sql"] + | | +- ID[@CanonicalImage = "L_SQL", @Image = "l_sql"] + | +- Expression[@CanonicalImage = "'SELECT * FROM DUAL'", @Image = "'SELECT * FROM DUAL'"] + | +- PrimaryPrefix[@CanonicalImage = "'SELECT * FROM DUAL'", @Image = "'SELECT * FROM DUAL'", @SelfModifier = false] + | +- Literal[@CanonicalImage = "'SELECT * FROM DUAL'", @Image = "'SELECT * FROM DUAL'"] + | +- StringLiteral[@CanonicalImage = "'SELECT * FROM DUAL'", @Image = "'SELECT * FROM DUAL'", @String = "SELECT * FROM DUAL"] + +- Statement[@CanonicalImage = null] + | +- UnlabelledStatement[@CanonicalImage = null] + | +- EmbeddedSqlStatement[@CanonicalImage = null] + | +- StringExpression[@CanonicalImage = "L_SQL", @Image = "l_sql"] + | | +- PrimaryPrefix[@CanonicalImage = "L_SQL", @Image = "l_sql", @SelfModifier = false] + | | +- SimpleExpression[@CanonicalImage = "L_SQL", @Image = "l_sql"] + | | +- Column[@CanonicalImage = "L_SQL", @Image = "l_sql"] + | | +- ID[@CanonicalImage = "L_SQL", @Image = "l_sql"] + | +- BulkCollectIntoClause[@CanonicalImage = null] + | +- CollectionName[@CanonicalImage = "L_DATA", @Image = "l_data"] + | +- ID[@CanonicalImage = "L_DATA", @Image = "l_data"] + +- ID[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE"] diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect2.pls b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect2.pls index bde3fe091e..51c5984d16 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect2.pls +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect2.pls @@ -1,3 +1,7 @@ +-- +-- BSD-style license; for more info see http://pmd.sourceforge.net/license.html +-- + CREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS -- TYPE t_data_key IS TABLE OF NUMBER INDEX BY BINARY_INTEGER; @@ -23,4 +27,4 @@ BEGIN EXECUTE IMMEDIATE l_sql BULK COLLECT INTO l_data_key, l_data_description USING p_rownum1, p_rownum2; -- -END EXAMPLE_PROCEDURE; \ No newline at end of file +END EXAMPLE_PROCEDURE; diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect2.txt b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect2.txt new file mode 100644 index 0000000000..379336f71f --- /dev/null +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect2.txt @@ -0,0 +1,221 @@ ++- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0, @Sourcecode = "-- +-- BSD-style license; for more info see http://pmd.sourceforge.net/license.html +-- + +CREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS + -- + TYPE t_data_key IS TABLE OF NUMBER INDEX BY BINARY_INTEGER; + TYPE t_data_description IS TABLE OF VARCHAR2(100) INDEX BY BINARY_INTEGER; + -- + l_data_key t_data_key; + l_data_description t_data_description; + l_sql VARCHAR2(500); + p_rownum1 NUMBER(20); + p_rownum2 NUMBER(20); + -- +BEGIN + -- + p_rownum1 := 10; + p_rownum2 := 30; + -- + l_sql := 'SELECT 1, ' || CHR(39) || 'First key' || CHR(39) || + ' FROM DUAL '||' WHERE ROWNUM <= :p_rownum1 ' || + 'UNION ALL '|| + 'SELECT 2, ' || CHR(39) || 'Second key ' || CHR(39) || + ' FROM DUAL'||' WHERE ROWNUM <= :p_rownum2 '; + -- + EXECUTE IMMEDIATE l_sql BULK COLLECT + INTO l_data_key, l_data_description USING p_rownum1, p_rownum2; + -- +END EXAMPLE_PROCEDURE; +"] + +- Global[@CanonicalImage = null] + +- ProgramUnit[@CanonicalImage = null, @MethodName = "EXAMPLE_PROCEDURE", @Name = "EXAMPLE_PROCEDURE", @ObjectName = null] + +- MethodDeclarator[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE", @ParameterCount = 1] + | +- ObjectNameDeclaration[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE"] + | +- ID[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE"] + +- DeclarativeSection[@CanonicalImage = null] + | +- DeclarativeUnit[@CanonicalImage = null] + | | +- SubTypeDefinition[@CanonicalImage = "T_DATA_KEY", @Image = "t_data_key"] + | | +- QualifiedID[@CanonicalImage = "T_DATA_KEY", @Image = "t_data_key"] + | | +- Datatype[@CanonicalImage = "NUMBER", @Image = "NUMBER", @TypeImage = "NUMBER"] + | | | +- ScalarDataTypeName[@CanonicalImage = "NUMBER", @Image = "NUMBER"] + | | +- Datatype[@CanonicalImage = "BINARY_INTEGER", @Image = "BINARY_INTEGER", @TypeImage = "BINARY_INTEGER"] + | | +- ScalarDataTypeName[@CanonicalImage = "BINARY_INTEGER", @Image = "BINARY_INTEGER"] + | +- DeclarativeUnit[@CanonicalImage = null] + | | +- SubTypeDefinition[@CanonicalImage = "T_DATA_DESCRIPTION", @Image = "t_data_description"] + | | +- QualifiedID[@CanonicalImage = "T_DATA_DESCRIPTION", @Image = "t_data_description"] + | | +- Datatype[@CanonicalImage = "VARCHAR2(100)", @Image = "VARCHAR2(100)", @TypeImage = "VARCHAR2(100)"] + | | | +- ScalarDataTypeName[@CanonicalImage = "VARCHAR2(100)", @Image = "VARCHAR2(100)"] + | | | +- NumericLiteral[@CanonicalImage = "100", @Image = "100"] + | | +- Datatype[@CanonicalImage = "BINARY_INTEGER", @Image = "BINARY_INTEGER", @TypeImage = "BINARY_INTEGER"] + | | +- ScalarDataTypeName[@CanonicalImage = "BINARY_INTEGER", @Image = "BINARY_INTEGER"] + | +- DeclarativeUnit[@CanonicalImage = null] + | | +- VariableOrConstantDeclaration[@CanonicalImage = null] + | | +- VariableOrConstantDeclarator[@CanonicalImage = "L_DATA_KEY T_DATA_KEY", @Image = "l_data_key t_data_key"] + | | +- VariableOrConstantDeclaratorId[@Array = false, @ArrayDepth = 0, @CanonicalImage = "L_DATA_KEY", @Image = "l_data_key"] + | | | +- ID[@CanonicalImage = "L_DATA_KEY", @Image = "l_data_key"] + | | +- Datatype[@CanonicalImage = "T_DATA_KEY", @Image = "t_data_key", @TypeImage = "t_data_key"] + | | +- QualifiedName[@CanonicalImage = "T_DATA_KEY", @Image = "t_data_key"] + | | +- UnqualifiedID[@CanonicalImage = "T_DATA_KEY", @Image = "t_data_key"] + | +- DeclarativeUnit[@CanonicalImage = null] + | | +- VariableOrConstantDeclaration[@CanonicalImage = null] + | | +- VariableOrConstantDeclarator[@CanonicalImage = "L_DATA_DESCRIPTION T_DATA_DESCRIPTION", @Image = "l_data_description t_data_description"] + | | +- VariableOrConstantDeclaratorId[@Array = false, @ArrayDepth = 0, @CanonicalImage = "L_DATA_DESCRIPTION", @Image = "l_data_description"] + | | | +- ID[@CanonicalImage = "L_DATA_DESCRIPTION", @Image = "l_data_description"] + | | +- Datatype[@CanonicalImage = "T_DATA_DESCRIPTION", @Image = "t_data_description", @TypeImage = "t_data_description"] + | | +- QualifiedName[@CanonicalImage = "T_DATA_DESCRIPTION", @Image = "t_data_description"] + | | +- UnqualifiedID[@CanonicalImage = "T_DATA_DESCRIPTION", @Image = "t_data_description"] + | +- DeclarativeUnit[@CanonicalImage = null] + | | +- VariableOrConstantDeclaration[@CanonicalImage = null] + | | +- VariableOrConstantDeclarator[@CanonicalImage = "L_SQL VARCHAR2(500)", @Image = "l_sql VARCHAR2(500)"] + | | +- VariableOrConstantDeclaratorId[@Array = false, @ArrayDepth = 0, @CanonicalImage = "L_SQL", @Image = "l_sql"] + | | | +- ID[@CanonicalImage = "L_SQL", @Image = "l_sql"] + | | +- Datatype[@CanonicalImage = "VARCHAR2(500)", @Image = "VARCHAR2(500)", @TypeImage = "VARCHAR2(500)"] + | | +- ScalarDataTypeName[@CanonicalImage = "VARCHAR2(500)", @Image = "VARCHAR2(500)"] + | | +- NumericLiteral[@CanonicalImage = "500", @Image = "500"] + | +- DeclarativeUnit[@CanonicalImage = null] + | | +- VariableOrConstantDeclaration[@CanonicalImage = null] + | | +- VariableOrConstantDeclarator[@CanonicalImage = "P_ROWNUM1 NUMBER(20)", @Image = "p_rownum1 NUMBER(20)"] + | | +- VariableOrConstantDeclaratorId[@Array = false, @ArrayDepth = 0, @CanonicalImage = "P_ROWNUM1", @Image = "p_rownum1"] + | | | +- ID[@CanonicalImage = "P_ROWNUM1", @Image = "p_rownum1"] + | | +- Datatype[@CanonicalImage = "NUMBER(20)", @Image = "NUMBER(20)", @TypeImage = "NUMBER(20)"] + | | +- ScalarDataTypeName[@CanonicalImage = "NUMBER(20)", @Image = "NUMBER(20)"] + | | +- NumericLiteral[@CanonicalImage = "20", @Image = "20"] + | +- DeclarativeUnit[@CanonicalImage = null] + | +- VariableOrConstantDeclaration[@CanonicalImage = null] + | +- VariableOrConstantDeclarator[@CanonicalImage = "P_ROWNUM2 NUMBER(20)", @Image = "p_rownum2 NUMBER(20)"] + | +- VariableOrConstantDeclaratorId[@Array = false, @ArrayDepth = 0, @CanonicalImage = "P_ROWNUM2", @Image = "p_rownum2"] + | | +- ID[@CanonicalImage = "P_ROWNUM2", @Image = "p_rownum2"] + | +- Datatype[@CanonicalImage = "NUMBER(20)", @Image = "NUMBER(20)", @TypeImage = "NUMBER(20)"] + | +- ScalarDataTypeName[@CanonicalImage = "NUMBER(20)", @Image = "NUMBER(20)"] + | +- NumericLiteral[@CanonicalImage = "20", @Image = "20"] + +- Statement[@CanonicalImage = null] + | +- UnlabelledStatement[@CanonicalImage = null] + | +- Expression[@CanonicalImage = "P_ROWNUM1 := 10", @Image = "p_rownum1 := 10"] + | +- Assignment[@CanonicalImage = "P_ROWNUM1 := 10", @Image = "p_rownum1 := 10"] + | +- PrimaryPrefix[@CanonicalImage = "P_ROWNUM1", @Image = "p_rownum1", @SelfModifier = false] + | | +- SimpleExpression[@CanonicalImage = "P_ROWNUM1", @Image = "p_rownum1"] + | | +- Column[@CanonicalImage = "P_ROWNUM1", @Image = "p_rownum1"] + | | +- ID[@CanonicalImage = "P_ROWNUM1", @Image = "p_rownum1"] + | +- Expression[@CanonicalImage = "10", @Image = "10"] + | +- PrimaryPrefix[@CanonicalImage = "10", @Image = "10", @SelfModifier = false] + | +- Literal[@CanonicalImage = "10", @Image = "10"] + | +- NumericLiteral[@CanonicalImage = "10", @Image = "10"] + +- Statement[@CanonicalImage = null] + | +- UnlabelledStatement[@CanonicalImage = null] + | +- Expression[@CanonicalImage = "P_ROWNUM2 := 30", @Image = "p_rownum2 := 30"] + | +- Assignment[@CanonicalImage = "P_ROWNUM2 := 30", @Image = "p_rownum2 := 30"] + | +- PrimaryPrefix[@CanonicalImage = "P_ROWNUM2", @Image = "p_rownum2", @SelfModifier = false] + | | +- SimpleExpression[@CanonicalImage = "P_ROWNUM2", @Image = "p_rownum2"] + | | +- Column[@CanonicalImage = "P_ROWNUM2", @Image = "p_rownum2"] + | | +- ID[@CanonicalImage = "P_ROWNUM2", @Image = "p_rownum2"] + | +- Expression[@CanonicalImage = "30", @Image = "30"] + | +- PrimaryPrefix[@CanonicalImage = "30", @Image = "30", @SelfModifier = false] + | +- Literal[@CanonicalImage = "30", @Image = "30"] + | +- NumericLiteral[@CanonicalImage = "30", @Image = "30"] + +- Statement[@CanonicalImage = null] + | +- UnlabelledStatement[@CanonicalImage = null] + | +- Expression[@CanonicalImage = "L_SQL := 'SELECT 1, ' || CHR || 'FIRST KEY' || CHR || ' FROM DUAL ' || ' WHERE ROWNUM <= :P_ROWNUM1 ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'SECOND KEY ' || CHR || ' FROM DUAL' || ' WHERE ROWNUM <= :P_ROWNUM2 '", @Image = "l_sql := 'SELECT 1, ' || CHR || 'First key' || CHR || ' FROM DUAL ' || ' WHERE ROWNUM <= :p_rownum1 ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'Second key ' || CHR || ' FROM DUAL' || ' WHERE ROWNUM <= :p_rownum2 '"] + | +- Assignment[@CanonicalImage = "L_SQL := 'SELECT 1, ' || CHR || 'FIRST KEY' || CHR || ' FROM DUAL ' || ' WHERE ROWNUM <= :P_ROWNUM1 ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'SECOND KEY ' || CHR || ' FROM DUAL' || ' WHERE ROWNUM <= :P_ROWNUM2 '", @Image = "l_sql := 'SELECT 1, ' || CHR || 'First key' || CHR || ' FROM DUAL ' || ' WHERE ROWNUM <= :p_rownum1 ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'Second key ' || CHR || ' FROM DUAL' || ' WHERE ROWNUM <= :p_rownum2 '"] + | +- PrimaryPrefix[@CanonicalImage = "L_SQL", @Image = "l_sql", @SelfModifier = false] + | | +- SimpleExpression[@CanonicalImage = "L_SQL", @Image = "l_sql"] + | | +- Column[@CanonicalImage = "L_SQL", @Image = "l_sql"] + | | +- ID[@CanonicalImage = "L_SQL", @Image = "l_sql"] + | +- Expression[@CanonicalImage = "'SELECT 1, ' || CHR || 'FIRST KEY' || CHR || ' FROM DUAL ' || ' WHERE ROWNUM <= :P_ROWNUM1 ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'SECOND KEY ' || CHR || ' FROM DUAL' || ' WHERE ROWNUM <= :P_ROWNUM2 '", @Image = "'SELECT 1, ' || CHR || 'First key' || CHR || ' FROM DUAL ' || ' WHERE ROWNUM <= :p_rownum1 ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'Second key ' || CHR || ' FROM DUAL' || ' WHERE ROWNUM <= :p_rownum2 '"] + | +- AdditiveExpression[@CanonicalImage = "'SELECT 1, ' || CHR || 'FIRST KEY' || CHR || ' FROM DUAL ' || ' WHERE ROWNUM <= :P_ROWNUM1 ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'SECOND KEY ' || CHR || ' FROM DUAL' || ' WHERE ROWNUM <= :P_ROWNUM2 '", @Image = "'SELECT 1, ' || CHR || 'First key' || CHR || ' FROM DUAL ' || ' WHERE ROWNUM <= :p_rownum1 ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'Second key ' || CHR || ' FROM DUAL' || ' WHERE ROWNUM <= :p_rownum2 '"] + | +- PrimaryPrefix[@CanonicalImage = "'SELECT 1, '", @Image = "'SELECT 1, '", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "'SELECT 1, '", @Image = "'SELECT 1, '"] + | | +- StringLiteral[@CanonicalImage = "'SELECT 1, '", @Image = "'SELECT 1, '", @String = "SELECT 1, "] + | +- PrimaryPrefix[@CanonicalImage = "CHR", @Image = "CHR", @SelfModifier = false] + | | +- FunctionCall[@CanonicalImage = "CHR", @Image = "CHR"] + | | +- FunctionName[@CanonicalImage = "CHR", @Image = "CHR"] + | | | +- ID[@CanonicalImage = "CHR", @Image = "CHR"] + | | +- Arguments[@ArgumentCount = 1, @CanonicalImage = null] + | | +- ArgumentList[@CanonicalImage = null] + | | +- Argument[@CanonicalImage = null] + | | +- Expression[@CanonicalImage = "39", @Image = "39"] + | | +- PrimaryPrefix[@CanonicalImage = "39", @Image = "39", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "39", @Image = "39"] + | | +- NumericLiteral[@CanonicalImage = "39", @Image = "39"] + | +- PrimaryPrefix[@CanonicalImage = "'FIRST KEY'", @Image = "'First key'", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "'FIRST KEY'", @Image = "'First key'"] + | | +- StringLiteral[@CanonicalImage = "'FIRST KEY'", @Image = "'First key'", @String = "First key"] + | +- PrimaryPrefix[@CanonicalImage = "CHR", @Image = "CHR", @SelfModifier = false] + | | +- FunctionCall[@CanonicalImage = "CHR", @Image = "CHR"] + | | +- FunctionName[@CanonicalImage = "CHR", @Image = "CHR"] + | | | +- ID[@CanonicalImage = "CHR", @Image = "CHR"] + | | +- Arguments[@ArgumentCount = 1, @CanonicalImage = null] + | | +- ArgumentList[@CanonicalImage = null] + | | +- Argument[@CanonicalImage = null] + | | +- Expression[@CanonicalImage = "39", @Image = "39"] + | | +- PrimaryPrefix[@CanonicalImage = "39", @Image = "39", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "39", @Image = "39"] + | | +- NumericLiteral[@CanonicalImage = "39", @Image = "39"] + | +- PrimaryPrefix[@CanonicalImage = "' FROM DUAL '", @Image = "' FROM DUAL '", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "' FROM DUAL '", @Image = "' FROM DUAL '"] + | | +- StringLiteral[@CanonicalImage = "' FROM DUAL '", @Image = "' FROM DUAL '", @String = " FROM DUAL "] + | +- PrimaryPrefix[@CanonicalImage = "' WHERE ROWNUM <= :P_ROWNUM1 '", @Image = "' WHERE ROWNUM <= :p_rownum1 '", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "' WHERE ROWNUM <= :P_ROWNUM1 '", @Image = "' WHERE ROWNUM <= :p_rownum1 '"] + | | +- StringLiteral[@CanonicalImage = "' WHERE ROWNUM <= :P_ROWNUM1 '", @Image = "' WHERE ROWNUM <= :p_rownum1 '", @String = " WHERE ROWNUM <= :p_rownum1 "] + | +- PrimaryPrefix[@CanonicalImage = "'UNION ALL '", @Image = "'UNION ALL '", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "'UNION ALL '", @Image = "'UNION ALL '"] + | | +- StringLiteral[@CanonicalImage = "'UNION ALL '", @Image = "'UNION ALL '", @String = "UNION ALL "] + | +- PrimaryPrefix[@CanonicalImage = "'SELECT 2, '", @Image = "'SELECT 2, '", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "'SELECT 2, '", @Image = "'SELECT 2, '"] + | | +- StringLiteral[@CanonicalImage = "'SELECT 2, '", @Image = "'SELECT 2, '", @String = "SELECT 2, "] + | +- PrimaryPrefix[@CanonicalImage = "CHR", @Image = "CHR", @SelfModifier = false] + | | +- FunctionCall[@CanonicalImage = "CHR", @Image = "CHR"] + | | +- FunctionName[@CanonicalImage = "CHR", @Image = "CHR"] + | | | +- ID[@CanonicalImage = "CHR", @Image = "CHR"] + | | +- Arguments[@ArgumentCount = 1, @CanonicalImage = null] + | | +- ArgumentList[@CanonicalImage = null] + | | +- Argument[@CanonicalImage = null] + | | +- Expression[@CanonicalImage = "39", @Image = "39"] + | | +- PrimaryPrefix[@CanonicalImage = "39", @Image = "39", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "39", @Image = "39"] + | | +- NumericLiteral[@CanonicalImage = "39", @Image = "39"] + | +- PrimaryPrefix[@CanonicalImage = "'SECOND KEY '", @Image = "'Second key '", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "'SECOND KEY '", @Image = "'Second key '"] + | | +- StringLiteral[@CanonicalImage = "'SECOND KEY '", @Image = "'Second key '", @String = "Second key "] + | +- PrimaryPrefix[@CanonicalImage = "CHR", @Image = "CHR", @SelfModifier = false] + | | +- FunctionCall[@CanonicalImage = "CHR", @Image = "CHR"] + | | +- FunctionName[@CanonicalImage = "CHR", @Image = "CHR"] + | | | +- ID[@CanonicalImage = "CHR", @Image = "CHR"] + | | +- Arguments[@ArgumentCount = 1, @CanonicalImage = null] + | | +- ArgumentList[@CanonicalImage = null] + | | +- Argument[@CanonicalImage = null] + | | +- Expression[@CanonicalImage = "39", @Image = "39"] + | | +- PrimaryPrefix[@CanonicalImage = "39", @Image = "39", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "39", @Image = "39"] + | | +- NumericLiteral[@CanonicalImage = "39", @Image = "39"] + | +- PrimaryPrefix[@CanonicalImage = "' FROM DUAL'", @Image = "' FROM DUAL'", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "' FROM DUAL'", @Image = "' FROM DUAL'"] + | | +- StringLiteral[@CanonicalImage = "' FROM DUAL'", @Image = "' FROM DUAL'", @String = " FROM DUAL"] + | +- PrimaryPrefix[@CanonicalImage = "' WHERE ROWNUM <= :P_ROWNUM2 '", @Image = "' WHERE ROWNUM <= :p_rownum2 '", @SelfModifier = false] + | +- Literal[@CanonicalImage = "' WHERE ROWNUM <= :P_ROWNUM2 '", @Image = "' WHERE ROWNUM <= :p_rownum2 '"] + | +- StringLiteral[@CanonicalImage = "' WHERE ROWNUM <= :P_ROWNUM2 '", @Image = "' WHERE ROWNUM <= :p_rownum2 '", @String = " WHERE ROWNUM <= :p_rownum2 "] + +- Statement[@CanonicalImage = null] + | +- UnlabelledStatement[@CanonicalImage = null] + | +- EmbeddedSqlStatement[@CanonicalImage = null] + | +- StringExpression[@CanonicalImage = "L_SQL", @Image = "l_sql"] + | | +- PrimaryPrefix[@CanonicalImage = "L_SQL", @Image = "l_sql", @SelfModifier = false] + | | +- SimpleExpression[@CanonicalImage = "L_SQL", @Image = "l_sql"] + | | +- Column[@CanonicalImage = "L_SQL", @Image = "l_sql"] + | | +- ID[@CanonicalImage = "L_SQL", @Image = "l_sql"] + | +- BulkCollectIntoClause[@CanonicalImage = null] + | | +- CollectionName[@CanonicalImage = "L_DATA_KEY", @Image = "l_data_key"] + | | | +- ID[@CanonicalImage = "L_DATA_KEY", @Image = "l_data_key"] + | | +- CollectionName[@CanonicalImage = "L_DATA_DESCRIPTION", @Image = "l_data_description"] + | | +- ID[@CanonicalImage = "L_DATA_DESCRIPTION", @Image = "l_data_description"] + | +- Expression[@CanonicalImage = "P_ROWNUM1", @Image = "p_rownum1"] + | | +- PrimaryPrefix[@CanonicalImage = "P_ROWNUM1", @Image = "p_rownum1", @SelfModifier = false] + | | +- SimpleExpression[@CanonicalImage = "P_ROWNUM1", @Image = "p_rownum1"] + | | +- Column[@CanonicalImage = "P_ROWNUM1", @Image = "p_rownum1"] + | | +- ID[@CanonicalImage = "P_ROWNUM1", @Image = "p_rownum1"] + | +- Expression[@CanonicalImage = "P_ROWNUM2", @Image = "p_rownum2"] + | +- PrimaryPrefix[@CanonicalImage = "P_ROWNUM2", @Image = "p_rownum2", @SelfModifier = false] + | +- SimpleExpression[@CanonicalImage = "P_ROWNUM2", @Image = "p_rownum2"] + | +- Column[@CanonicalImage = "P_ROWNUM2", @Image = "p_rownum2"] + | +- ID[@CanonicalImage = "P_ROWNUM2", @Image = "p_rownum2"] + +- ID[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE"] diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect3.pls b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect3.pls index 74270792e3..9fac7557d8 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect3.pls +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect3.pls @@ -1,3 +1,7 @@ +-- +-- BSD-style license; for more info see http://pmd.sourceforge.net/license.html +-- + CREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS -- TYPE t_data_key IS TABLE OF NUMBER INDEX BY BINARY_INTEGER; @@ -18,4 +22,4 @@ BEGIN EXECUTE IMMEDIATE l_sql BULK COLLECT INTO l_data_key, l_data_description; -- -END EXAMPLE_PROCEDURE; \ No newline at end of file +END EXAMPLE_PROCEDURE; diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect3.txt b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect3.txt new file mode 100644 index 0000000000..f8d384e4c9 --- /dev/null +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect3.txt @@ -0,0 +1,160 @@ ++- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0, @Sourcecode = "-- +-- BSD-style license; for more info see http://pmd.sourceforge.net/license.html +-- + +CREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS + -- + TYPE t_data_key IS TABLE OF NUMBER INDEX BY BINARY_INTEGER; + TYPE t_data_description IS TABLE OF VARCHAR2(100) INDEX BY BINARY_INTEGER; + -- + l_data_key t_data_key; + l_data_description t_data_description; + l_sql VARCHAR2(500); + -- +BEGIN + -- + l_sql := 'SELECT 1, ' || CHR(39) || 'First key' || CHR(39) || + ' FROM DUAL '|| + 'UNION ALL '|| + 'SELECT 2, ' || CHR(39) || 'Second key ' || CHR(39) || + ' FROM DUAL'; + -- + EXECUTE IMMEDIATE l_sql BULK COLLECT + INTO l_data_key, l_data_description; + -- +END EXAMPLE_PROCEDURE; +"] + +- Global[@CanonicalImage = null] + +- ProgramUnit[@CanonicalImage = null, @MethodName = "EXAMPLE_PROCEDURE", @Name = "EXAMPLE_PROCEDURE", @ObjectName = null] + +- MethodDeclarator[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE", @ParameterCount = 1] + | +- ObjectNameDeclaration[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE"] + | +- ID[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE"] + +- DeclarativeSection[@CanonicalImage = null] + | +- DeclarativeUnit[@CanonicalImage = null] + | | +- SubTypeDefinition[@CanonicalImage = "T_DATA_KEY", @Image = "t_data_key"] + | | +- QualifiedID[@CanonicalImage = "T_DATA_KEY", @Image = "t_data_key"] + | | +- Datatype[@CanonicalImage = "NUMBER", @Image = "NUMBER", @TypeImage = "NUMBER"] + | | | +- ScalarDataTypeName[@CanonicalImage = "NUMBER", @Image = "NUMBER"] + | | +- Datatype[@CanonicalImage = "BINARY_INTEGER", @Image = "BINARY_INTEGER", @TypeImage = "BINARY_INTEGER"] + | | +- ScalarDataTypeName[@CanonicalImage = "BINARY_INTEGER", @Image = "BINARY_INTEGER"] + | +- DeclarativeUnit[@CanonicalImage = null] + | | +- SubTypeDefinition[@CanonicalImage = "T_DATA_DESCRIPTION", @Image = "t_data_description"] + | | +- QualifiedID[@CanonicalImage = "T_DATA_DESCRIPTION", @Image = "t_data_description"] + | | +- Datatype[@CanonicalImage = "VARCHAR2(100)", @Image = "VARCHAR2(100)", @TypeImage = "VARCHAR2(100)"] + | | | +- ScalarDataTypeName[@CanonicalImage = "VARCHAR2(100)", @Image = "VARCHAR2(100)"] + | | | +- NumericLiteral[@CanonicalImage = "100", @Image = "100"] + | | +- Datatype[@CanonicalImage = "BINARY_INTEGER", @Image = "BINARY_INTEGER", @TypeImage = "BINARY_INTEGER"] + | | +- ScalarDataTypeName[@CanonicalImage = "BINARY_INTEGER", @Image = "BINARY_INTEGER"] + | +- DeclarativeUnit[@CanonicalImage = null] + | | +- VariableOrConstantDeclaration[@CanonicalImage = null] + | | +- VariableOrConstantDeclarator[@CanonicalImage = "L_DATA_KEY T_DATA_KEY", @Image = "l_data_key t_data_key"] + | | +- VariableOrConstantDeclaratorId[@Array = false, @ArrayDepth = 0, @CanonicalImage = "L_DATA_KEY", @Image = "l_data_key"] + | | | +- ID[@CanonicalImage = "L_DATA_KEY", @Image = "l_data_key"] + | | +- Datatype[@CanonicalImage = "T_DATA_KEY", @Image = "t_data_key", @TypeImage = "t_data_key"] + | | +- QualifiedName[@CanonicalImage = "T_DATA_KEY", @Image = "t_data_key"] + | | +- UnqualifiedID[@CanonicalImage = "T_DATA_KEY", @Image = "t_data_key"] + | +- DeclarativeUnit[@CanonicalImage = null] + | | +- VariableOrConstantDeclaration[@CanonicalImage = null] + | | +- VariableOrConstantDeclarator[@CanonicalImage = "L_DATA_DESCRIPTION T_DATA_DESCRIPTION", @Image = "l_data_description t_data_description"] + | | +- VariableOrConstantDeclaratorId[@Array = false, @ArrayDepth = 0, @CanonicalImage = "L_DATA_DESCRIPTION", @Image = "l_data_description"] + | | | +- ID[@CanonicalImage = "L_DATA_DESCRIPTION", @Image = "l_data_description"] + | | +- Datatype[@CanonicalImage = "T_DATA_DESCRIPTION", @Image = "t_data_description", @TypeImage = "t_data_description"] + | | +- QualifiedName[@CanonicalImage = "T_DATA_DESCRIPTION", @Image = "t_data_description"] + | | +- UnqualifiedID[@CanonicalImage = "T_DATA_DESCRIPTION", @Image = "t_data_description"] + | +- DeclarativeUnit[@CanonicalImage = null] + | +- VariableOrConstantDeclaration[@CanonicalImage = null] + | +- VariableOrConstantDeclarator[@CanonicalImage = "L_SQL VARCHAR2(500)", @Image = "l_sql VARCHAR2(500)"] + | +- VariableOrConstantDeclaratorId[@Array = false, @ArrayDepth = 0, @CanonicalImage = "L_SQL", @Image = "l_sql"] + | | +- ID[@CanonicalImage = "L_SQL", @Image = "l_sql"] + | +- Datatype[@CanonicalImage = "VARCHAR2(500)", @Image = "VARCHAR2(500)", @TypeImage = "VARCHAR2(500)"] + | +- ScalarDataTypeName[@CanonicalImage = "VARCHAR2(500)", @Image = "VARCHAR2(500)"] + | +- NumericLiteral[@CanonicalImage = "500", @Image = "500"] + +- Statement[@CanonicalImage = null] + | +- UnlabelledStatement[@CanonicalImage = null] + | +- Expression[@CanonicalImage = "L_SQL := 'SELECT 1, ' || CHR || 'FIRST KEY' || CHR || ' FROM DUAL ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'SECOND KEY ' || CHR || ' FROM DUAL'", @Image = "l_sql := 'SELECT 1, ' || CHR || 'First key' || CHR || ' FROM DUAL ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'Second key ' || CHR || ' FROM DUAL'"] + | +- Assignment[@CanonicalImage = "L_SQL := 'SELECT 1, ' || CHR || 'FIRST KEY' || CHR || ' FROM DUAL ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'SECOND KEY ' || CHR || ' FROM DUAL'", @Image = "l_sql := 'SELECT 1, ' || CHR || 'First key' || CHR || ' FROM DUAL ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'Second key ' || CHR || ' FROM DUAL'"] + | +- PrimaryPrefix[@CanonicalImage = "L_SQL", @Image = "l_sql", @SelfModifier = false] + | | +- SimpleExpression[@CanonicalImage = "L_SQL", @Image = "l_sql"] + | | +- Column[@CanonicalImage = "L_SQL", @Image = "l_sql"] + | | +- ID[@CanonicalImage = "L_SQL", @Image = "l_sql"] + | +- Expression[@CanonicalImage = "'SELECT 1, ' || CHR || 'FIRST KEY' || CHR || ' FROM DUAL ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'SECOND KEY ' || CHR || ' FROM DUAL'", @Image = "'SELECT 1, ' || CHR || 'First key' || CHR || ' FROM DUAL ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'Second key ' || CHR || ' FROM DUAL'"] + | +- AdditiveExpression[@CanonicalImage = "'SELECT 1, ' || CHR || 'FIRST KEY' || CHR || ' FROM DUAL ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'SECOND KEY ' || CHR || ' FROM DUAL'", @Image = "'SELECT 1, ' || CHR || 'First key' || CHR || ' FROM DUAL ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'Second key ' || CHR || ' FROM DUAL'"] + | +- PrimaryPrefix[@CanonicalImage = "'SELECT 1, '", @Image = "'SELECT 1, '", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "'SELECT 1, '", @Image = "'SELECT 1, '"] + | | +- StringLiteral[@CanonicalImage = "'SELECT 1, '", @Image = "'SELECT 1, '", @String = "SELECT 1, "] + | +- PrimaryPrefix[@CanonicalImage = "CHR", @Image = "CHR", @SelfModifier = false] + | | +- FunctionCall[@CanonicalImage = "CHR", @Image = "CHR"] + | | +- FunctionName[@CanonicalImage = "CHR", @Image = "CHR"] + | | | +- ID[@CanonicalImage = "CHR", @Image = "CHR"] + | | +- Arguments[@ArgumentCount = 1, @CanonicalImage = null] + | | +- ArgumentList[@CanonicalImage = null] + | | +- Argument[@CanonicalImage = null] + | | +- Expression[@CanonicalImage = "39", @Image = "39"] + | | +- PrimaryPrefix[@CanonicalImage = "39", @Image = "39", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "39", @Image = "39"] + | | +- NumericLiteral[@CanonicalImage = "39", @Image = "39"] + | +- PrimaryPrefix[@CanonicalImage = "'FIRST KEY'", @Image = "'First key'", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "'FIRST KEY'", @Image = "'First key'"] + | | +- StringLiteral[@CanonicalImage = "'FIRST KEY'", @Image = "'First key'", @String = "First key"] + | +- PrimaryPrefix[@CanonicalImage = "CHR", @Image = "CHR", @SelfModifier = false] + | | +- FunctionCall[@CanonicalImage = "CHR", @Image = "CHR"] + | | +- FunctionName[@CanonicalImage = "CHR", @Image = "CHR"] + | | | +- ID[@CanonicalImage = "CHR", @Image = "CHR"] + | | +- Arguments[@ArgumentCount = 1, @CanonicalImage = null] + | | +- ArgumentList[@CanonicalImage = null] + | | +- Argument[@CanonicalImage = null] + | | +- Expression[@CanonicalImage = "39", @Image = "39"] + | | +- PrimaryPrefix[@CanonicalImage = "39", @Image = "39", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "39", @Image = "39"] + | | +- NumericLiteral[@CanonicalImage = "39", @Image = "39"] + | +- PrimaryPrefix[@CanonicalImage = "' FROM DUAL '", @Image = "' FROM DUAL '", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "' FROM DUAL '", @Image = "' FROM DUAL '"] + | | +- StringLiteral[@CanonicalImage = "' FROM DUAL '", @Image = "' FROM DUAL '", @String = " FROM DUAL "] + | +- PrimaryPrefix[@CanonicalImage = "'UNION ALL '", @Image = "'UNION ALL '", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "'UNION ALL '", @Image = "'UNION ALL '"] + | | +- StringLiteral[@CanonicalImage = "'UNION ALL '", @Image = "'UNION ALL '", @String = "UNION ALL "] + | +- PrimaryPrefix[@CanonicalImage = "'SELECT 2, '", @Image = "'SELECT 2, '", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "'SELECT 2, '", @Image = "'SELECT 2, '"] + | | +- StringLiteral[@CanonicalImage = "'SELECT 2, '", @Image = "'SELECT 2, '", @String = "SELECT 2, "] + | +- PrimaryPrefix[@CanonicalImage = "CHR", @Image = "CHR", @SelfModifier = false] + | | +- FunctionCall[@CanonicalImage = "CHR", @Image = "CHR"] + | | +- FunctionName[@CanonicalImage = "CHR", @Image = "CHR"] + | | | +- ID[@CanonicalImage = "CHR", @Image = "CHR"] + | | +- Arguments[@ArgumentCount = 1, @CanonicalImage = null] + | | +- ArgumentList[@CanonicalImage = null] + | | +- Argument[@CanonicalImage = null] + | | +- Expression[@CanonicalImage = "39", @Image = "39"] + | | +- PrimaryPrefix[@CanonicalImage = "39", @Image = "39", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "39", @Image = "39"] + | | +- NumericLiteral[@CanonicalImage = "39", @Image = "39"] + | +- PrimaryPrefix[@CanonicalImage = "'SECOND KEY '", @Image = "'Second key '", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "'SECOND KEY '", @Image = "'Second key '"] + | | +- StringLiteral[@CanonicalImage = "'SECOND KEY '", @Image = "'Second key '", @String = "Second key "] + | +- PrimaryPrefix[@CanonicalImage = "CHR", @Image = "CHR", @SelfModifier = false] + | | +- FunctionCall[@CanonicalImage = "CHR", @Image = "CHR"] + | | +- FunctionName[@CanonicalImage = "CHR", @Image = "CHR"] + | | | +- ID[@CanonicalImage = "CHR", @Image = "CHR"] + | | +- Arguments[@ArgumentCount = 1, @CanonicalImage = null] + | | +- ArgumentList[@CanonicalImage = null] + | | +- Argument[@CanonicalImage = null] + | | +- Expression[@CanonicalImage = "39", @Image = "39"] + | | +- PrimaryPrefix[@CanonicalImage = "39", @Image = "39", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "39", @Image = "39"] + | | +- NumericLiteral[@CanonicalImage = "39", @Image = "39"] + | +- PrimaryPrefix[@CanonicalImage = "' FROM DUAL'", @Image = "' FROM DUAL'", @SelfModifier = false] + | +- Literal[@CanonicalImage = "' FROM DUAL'", @Image = "' FROM DUAL'"] + | +- StringLiteral[@CanonicalImage = "' FROM DUAL'", @Image = "' FROM DUAL'", @String = " FROM DUAL"] + +- Statement[@CanonicalImage = null] + | +- UnlabelledStatement[@CanonicalImage = null] + | +- EmbeddedSqlStatement[@CanonicalImage = null] + | +- StringExpression[@CanonicalImage = "L_SQL", @Image = "l_sql"] + | | +- PrimaryPrefix[@CanonicalImage = "L_SQL", @Image = "l_sql", @SelfModifier = false] + | | +- SimpleExpression[@CanonicalImage = "L_SQL", @Image = "l_sql"] + | | +- Column[@CanonicalImage = "L_SQL", @Image = "l_sql"] + | | +- ID[@CanonicalImage = "L_SQL", @Image = "l_sql"] + | +- BulkCollectIntoClause[@CanonicalImage = null] + | +- CollectionName[@CanonicalImage = "L_DATA_KEY", @Image = "l_data_key"] + | | +- ID[@CanonicalImage = "L_DATA_KEY", @Image = "l_data_key"] + | +- CollectionName[@CanonicalImage = "L_DATA_DESCRIPTION", @Image = "l_data_description"] + | +- ID[@CanonicalImage = "L_DATA_DESCRIPTION", @Image = "l_data_description"] + +- ID[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE"] diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup0.pls b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup0.pls index 0026e24d5d..d283bc7619 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup0.pls +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup0.pls @@ -1,3 +1,7 @@ +-- +-- BSD-style license; for more info see http://pmd.sourceforge.net/license.html +-- + CREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS -- CURSOR c_example IS diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup0.txt b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup0.txt index 0602c49949..aaa2464d78 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup0.txt +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup0.txt @@ -1,4 +1,8 @@ -+- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0, @Sourcecode = "CREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS ++- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0, @Sourcecode = "-- +-- BSD-style license; for more info see http://pmd.sourceforge.net/license.html +-- + +CREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS -- CURSOR c_example IS SELECT a.owner, u.object_name, p.aggregate diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup1.pls b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup1.pls index c5fd5d411d..9a88deabfc 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup1.pls +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup1.pls @@ -1,3 +1,7 @@ +-- +-- BSD-style license; for more info see http://pmd.sourceforge.net/license.html +-- + CREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS -- CURSOR c_example IS diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup1.txt b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup1.txt index 1d77da1f68..8bc9983c66 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup1.txt +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup1.txt @@ -1,4 +1,8 @@ -+- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0, @Sourcecode = "CREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS ++- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0, @Sourcecode = "-- +-- BSD-style license; for more info see http://pmd.sourceforge.net/license.html +-- + +CREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS -- CURSOR c_example IS SELECT a.owner, u.object_name, p.aggregate diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup2.pls b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup2.pls index cfd982322c..27696d02e9 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup2.pls +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup2.pls @@ -1,3 +1,7 @@ +-- +-- BSD-style license; for more info see http://pmd.sourceforge.net/license.html +-- + CREATE OR REPLACE PROCEDURE TEST_PROCEDURE IS -- CURSOR c_test IS diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup2.txt b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup2.txt index 329d2f56ae..ba0d002fba 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup2.txt +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup2.txt @@ -1,4 +1,8 @@ -+- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0, @Sourcecode = "CREATE OR REPLACE PROCEDURE TEST_PROCEDURE IS ++- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0, @Sourcecode = "-- +-- BSD-style license; for more info see http://pmd.sourceforge.net/license.html +-- + +CREATE OR REPLACE PROCEDURE TEST_PROCEDURE IS -- CURSOR c_test IS SELECT si.sid, sn.name, sa.age, ss.score, sp.parent From 35b6cc79caddee2f6f2efbd0659efffb98967bd6 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 28 Apr 2022 10:57:59 +0200 Subject: [PATCH 144/180] [plsql] Refactor execute immediate statement - It is now more compliant to the specification - Add new AST node DynamicReturnClause --- pmd-plsql/etc/grammar/PldocAST.jjt | 26 ++++++++++++++----- .../plsql/ast/PLSQLParserVisitorAdapter.java | 5 ++++ .../lang/plsql/rule/AbstractPLSQLRule.java | 6 +++++ 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/pmd-plsql/etc/grammar/PldocAST.jjt b/pmd-plsql/etc/grammar/PldocAST.jjt index 7013c9dd44..769382e274 100644 --- a/pmd-plsql/etc/grammar/PldocAST.jjt +++ b/pmd-plsql/etc/grammar/PldocAST.jjt @@ -2387,7 +2387,8 @@ ASTUnlabelledStatement UnlabelledStatement() : | OpenStatement() ";" | FetchStatement() ";" | Block() ";" - | LOOKAHEAD(2) EmbeddedSqlStatement() + | // Lookahead for EXECUTE IMMEDIATE to distinguish an identifier named "EXECUTE" from execute statement + LOOKAHEAD(2) EmbeddedSqlStatement() ";" | PipelineStatement() ";" | ConditionalCompilationStatement() // Conditional Compilation works outside the normal parsing rules | InlinePragma() ";" @@ -2821,12 +2822,23 @@ ASTEmbeddedSqlStatement EmbeddedSqlStatement() : {} { StringExpression() - [ LOOKAHEAD() BulkCollectIntoClause() ] //#3687 Invoke this method to parse BULK COLLECT - [ Name() ("," Name())* ] - [ UsingClause() ] - [ ( | ) Expression() ("," Expression())*] ";" - // PIPELINED FUNCTION OUTPUT - { return jjtThis ; } + [ + ( IntoClause() | BulkCollectIntoClause() ) [ UsingClause() ] + | UsingClause() [ DynamicReturnClause() ] + | DynamicReturnClause() + ] + { return jjtThis; } +} + +/** +* https://docs.oracle.com/en/database/oracle/oracle-database/18/lnpls/RETURNING-INTO-clause.html#GUID-38F735B9-1100-45AF-AE71-18FB74A899BE +*/ +ASTDynamicReturnClause DynamicReturnClause() : +{} +{ + ( | ) + ( IntoClause() | BulkCollectIntoClause() ) + { return jjtThis; } } void UsingClause() #void : 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 81e247e122..7d9a4f3fce 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 @@ -1116,4 +1116,9 @@ public class PLSQLParserVisitorAdapter implements PLSQLParserVisitor { public Object visit(ASTCursorSpecification node, Object data) { return visit((PLSQLNode) node, data); } + + @Override + public Object visit(ASTDynamicReturnClause 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 b424b36e8d..a89a524383 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 @@ -66,6 +66,7 @@ import net.sourceforge.pmd.lang.plsql.ast.ASTDeclarativeSection; import net.sourceforge.pmd.lang.plsql.ast.ASTDeclarativeUnit; import net.sourceforge.pmd.lang.plsql.ast.ASTDeleteStatement; import net.sourceforge.pmd.lang.plsql.ast.ASTDirectory; +import net.sourceforge.pmd.lang.plsql.ast.ASTDynamicReturnClause; import net.sourceforge.pmd.lang.plsql.ast.ASTElseClause; import net.sourceforge.pmd.lang.plsql.ast.ASTElsifClause; import net.sourceforge.pmd.lang.plsql.ast.ASTEmbeddedSqlStatement; @@ -1440,6 +1441,11 @@ public abstract class AbstractPLSQLRule extends AbstractRule implements PLSQLPar return visit((PLSQLNode) node, data); } + @Override + public Object visit(ASTDynamicReturnClause node, Object data) { + return visit((PLSQLNode) node, data); + } + // CPD-ON /* From 8370d6253d3f4cd1b0a0ab90a3c2e3f824519482 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 28 Apr 2022 11:34:25 +0200 Subject: [PATCH 145/180] [plsql] Fix usage of "IN" - it is a reserved word --- pmd-plsql/etc/grammar/PldocAST.jjt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pmd-plsql/etc/grammar/PldocAST.jjt b/pmd-plsql/etc/grammar/PldocAST.jjt index 769382e274..fbca5177c9 100644 --- a/pmd-plsql/etc/grammar/PldocAST.jjt +++ b/pmd-plsql/etc/grammar/PldocAST.jjt @@ -2823,7 +2823,8 @@ ASTEmbeddedSqlStatement EmbeddedSqlStatement() : { StringExpression() [ - ( IntoClause() | BulkCollectIntoClause() ) [ UsingClause() ] + IntoClause() [ UsingClause() ] + | BulkCollectIntoClause() [ UsingClause() ] | UsingClause() [ DynamicReturnClause() ] | DynamicReturnClause() ] @@ -2844,7 +2845,8 @@ ASTDynamicReturnClause DynamicReturnClause() : void UsingClause() #void : {} { - [ [ ] | ] Expression() ("," [ [ ] | ] Expression())* + [ [ ] | ] Expression() + ( "," [ [ ] | ] Expression() )* } ASTPipelineStatement PipelineStatement() : @@ -6600,7 +6602,6 @@ ASTID ID(): {} //20120501 | | //SYNTAX //20120501 | - | //RESERVED WORD | //RESERVED WORD //20120501 | | //SYNTAX //RESERVED WORD @@ -6833,7 +6834,6 @@ ASTQualifiedID QualifiedID(): {} //20120501 | // //20120501 | - // // //20120501 | // From 061d0d67249f23e9618c7ad90de5518c499c42f1 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 28 Apr 2022 11:35:52 +0200 Subject: [PATCH 146/180] Add @Scrsloota as a contributor --- .all-contributorsrc | 9 ++++ docs/pages/pmd/projectdocs/credits.md | 75 ++++++++++++++------------- 2 files changed, 47 insertions(+), 37 deletions(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 4a058b2ad4..717e21a7d5 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6612,6 +6612,15 @@ "contributions": [ "code" ] + }, + { + "login": "Scrsloota", + "name": "Scrsloota", + "avatar_url": "https://avatars.githubusercontent.com/u/91131546?v=4", + "profile": "https://github.com/Scrsloota", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 7, diff --git a/docs/pages/pmd/projectdocs/credits.md b/docs/pages/pmd/projectdocs/credits.md index 6902116903..c0c5daead0 100644 --- a/docs/pages/pmd/projectdocs/credits.md +++ b/docs/pages/pmd/projectdocs/credits.md @@ -609,338 +609,339 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Scott Wells

🐛 💻 +
Scrsloota

💻
Sebastian Bögl

🐛
Sebastian Schuberth

🐛
Sebastian Schwarz

🐛
Sergey Gorbaty

🐛
Sergey Kozlov

🐛 -
Sergey Yanzin

💻 🐛 +
Sergey Yanzin

💻 🐛
Seth Wilcox

💻
Shubham

💻 🐛
Simon Xiao

🐛
Srinivasan Venkatachalam

🐛
Stanislav Gromov

🐛
Stanislav Myachenkov

💻 -
Stefan Birkner

🐛 +
Stefan Birkner

🐛
Stefan Bohn

🐛
Stefan Endrullis

🐛
Stefan Klöss-Schuster

🐛
Stefan Wolf

🐛
Stephan H. Wissel

🐛
Stephen

🐛 -
Stephen Friedrich

🐛 +
Stephen Friedrich

🐛
Steve Babula

💻
Stexxe

🐛
Stian Lågstad

🐛
StuartClayton5

🐛
Supun Arunoda

🐛
Suren Abrahamyan

🐛 -
SwatiBGupta1110

🐛 +
SwatiBGupta1110

🐛
SyedThoufich

🐛
Szymon Sasin

🐛
T-chuangxin

🐛
TERAI Atsuhiro

🐛
TIOBE Software

💻 🐛
Taylor Smock

🐛 -
Techeira Damián

💻 🐛 +
Techeira Damián

💻 🐛
Ted Husted

🐛
TehBakker

🐛
The Gitter Badger

🐛
Theodoor

🐛
Thiago Henrique Hüpner

🐛
Thibault Meyer

🐛 -
Thomas Güttler

🐛 +
Thomas Güttler

🐛
Thomas Jones-Low

🐛
Thomas Smith

💻 🐛
ThrawnCA

🐛
Thunderforge

💻 🐛
Tim van der Lippe

🐛
Tobias Weimer

💻 🐛 -
Tom Daly

🐛 +
Tom Daly

🐛
Tomer Figenblat

🐛
Tomi De Lucca

💻 🐛
Torsten Kleiber

🐛
TrackerSB

🐛
Ullrich Hafner

🐛
Utku Cuhadaroglu

💻 🐛 -
Valentin Brandl

🐛 +
Valentin Brandl

🐛
Valeria

🐛
Vasily Anisimov

🐛
Vickenty Fesunov

🐛
Victor Noël

🐛
Vincent Galloy

💻
Vincent HUYNH

🐛 -
Vincent Maurin

🐛 +
Vincent Maurin

🐛
Vincent Privat

🐛
Vishhwas

🐛
Vitaly

🐛
Vitaly Polonetsky

🐛
Vojtech Polivka

🐛
Vsevolod Zholobov

🐛 -
Vyom Yadav

💻 +
Vyom Yadav

💻
Wang Shidong

🐛
Waqas Ahmed

🐛
Wayne J. Earl

🐛
Wchenghui

🐛
Will Winder

🐛
William Brockhus

💻 🐛 -
Wilson Kurniawan

🐛 +
Wilson Kurniawan

🐛
Wim Deblauwe

🐛
Woongsik Choi

🐛
XenoAmess

💻 🐛
Yang

💻
YaroslavTER

🐛
Young Chan

💻 🐛 -
YuJin Kim

🐛 +
YuJin Kim

🐛
Yuri Dolzhenko

🐛
Yurii Dubinka

🐛
Zoltan Farkas

🐛
Zustin

🐛
aaronhurst-google

🐛
alexmodis

🐛 -
andreoss

🐛 +
andreoss

🐛
andrey81inmd

💻 🐛
anicoara

🐛
arunprasathav

🐛
asiercamara

🐛
astillich-igniti

💻
avesolovksyy

🐛 -
avishvat

🐛 +
avishvat

🐛
avivmu

🐛
axelbarfod1

🐛
b-3-n

🐛
balbhadra9

🐛
base23de

🐛
bergander

🐛 -
berkam

💻 🐛 +
berkam

💻 🐛
breizh31

🐛
caesarkim

🐛
carolyujing

🐛
cesares-basilico

🐛
chrite

🐛
cobratbq

🐛 -
coladict

🐛 +
coladict

🐛
cosmoJFH

🐛
cristalp

🐛
crunsk

🐛
cwholmes

🐛
cyberjj999

🐛
cyw3

🐛 -
d1ss0nanz

🐛 +
d1ss0nanz

🐛
danbrycefairsailcom

🐛
dariansanity

🐛
darrenmiliband

🐛
davidburstrom

🐛
dbirkman-paloalto

🐛
deepak-patra

🐛 -
dependabot[bot]

💻 🐛 +
dependabot[bot]

💻 🐛
dinesh150

🐛
diziaq

🐛
dreaminpast123

🐛
duanyanan

🐛
dutt-sanjay

🐛
dylanleung

🐛 -
dzeigler

🐛 +
dzeigler

🐛
ekkirala

🐛
emersonmoura

🐛
fairy

🐛
filiprafalowicz

💻
foxmason

🐛
frankegabor

🐛 -
frankl

🐛 +
frankl

🐛
freafrea

🐛
fsapatin

🐛
gracia19

🐛
guo fei

🐛
gurmsc5

🐛
gwilymatgearset

💻 🐛 -
haigsn

🐛 +
haigsn

🐛
hemanshu070

🐛
henrik242

🐛
hongpuwu

🐛
hvbtup

💻 🐛
igniti GmbH

🐛
ilovezfs

🐛 -
itaigilo

🐛 +
itaigilo

🐛
jakivey32

🐛
jbennett2091

🐛
jcamerin

🐛
jkeener1

🐛
jmetertea

🐛
johnra2

💻 -
josemanuelrolon

💻 🐛 +
josemanuelrolon

💻 🐛
kabroxiko

💻 🐛
karwer

🐛
kaulonline

🐛
kdaemonv

🐛
kenji21

💻 🐛
kfranic

🐛 -
khalidkh

🐛 +
khalidkh

🐛
krzyk

🐛
lasselindqvist

🐛
lihuaib

🐛
lonelyma1021

🐛
lpeddy

🐛
lujiefsi

💻 -
lyriccoder

🐛 +
lyriccoder

🐛
marcelmore

🐛
matchbox

🐛
matthiaskraaz

🐛
meandonlyme

🐛
mikesive

🐛
milossesic

🐛 -
mriddell95

🐛 +
mriddell95

🐛
mrlzh

🐛
msloan

🐛
mucharlaravalika

🐛
mvenneman

🐛
nareshl119

🐛
nicolas-harraudeau-sonarsource

🐛 -
noerremark

🐛 +
noerremark

🐛
novsirion

🐛
oggboy

🐛
oinume

🐛
orimarko

💻 🐛
pallavi agarwal

🐛
parksungrin

🐛 -
patpatpat123

🐛 +
patpatpat123

🐛
patriksevallius

🐛
pbrajesh1

🐛
phoenix384

🐛
piotrszymanski-sc

💻
plan3d

🐛
poojasix

🐛 -
prabhushrikant

🐛 +
prabhushrikant

🐛
pujitha8783

🐛
r-r-a-j

🐛
raghujayjunk

🐛
rajeshveera

🐛
rajeswarreddy88

🐛
recdevs

🐛 -
reudismam

💻 🐛 +
reudismam

💻 🐛
rijkt

🐛
rillig-tk

🐛
rmohan20

💻 🐛
rxmicro

🐛
ryan-gustafson

💻 🐛
sabi0

🐛 -
scais

🐛 +
scais

🐛
sebbASF

🐛
sergeygorbaty

💻
shilko2013

🐛
simeonKondr

🐛
snajberk

🐛
sniperrifle2004

🐛 -
snuyanzin

🐛 💻 +
snuyanzin

🐛 💻
sratz

🐛
stonio

🐛
sturton

💻 🐛
sudharmohan

🐛
suruchidawar

🐛
svenfinitiv

🐛 -
tashiscool

🐛 +
tashiscool

🐛
test-git-hook

🐛
testation21

💻 🐛
thanosa

🐛
tiandiyixian

🐛
tobwoerk

🐛
tprouvot

🐛 -
trentchilders

🐛 +
trentchilders

🐛
triandicAnt

🐛
trishul14

🐛
tsui

🐛
winhkey

🐛
witherspore

🐛
wjljack

🐛 -
wuchiuwong

🐛 +
wuchiuwong

🐛
xingsong

🐛
xioayuge

🐛
xnYi9wRezm

💻 🐛
xuanuy

🐛
xyf0921

🐛
yalechen-cyw3

🐛 -
yasuharu-sato

🐛 +
yasuharu-sato

🐛
zenglian

🐛
zgrzyt93

💻 🐛
zh3ng

🐛
zt_soft

🐛
ztt79

🐛
zzzzfeng

🐛 -
Árpád Magosányi

🐛 +
Árpád Magosányi

🐛
任贵杰

🐛 From 84b6cfe93f7518868d2bb491dc0e43b4219262da Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 28 Apr 2022 11:38:20 +0200 Subject: [PATCH 147/180] [doc] Update release notes (#3687, #3935) --- 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 962f226a13..4d4eca65f5 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -35,6 +35,7 @@ This is a {{ site.pmd.release_type }} release. * [#3910](https://github.com/pmd/pmd/pull/3910): \[java] UnusedPrivateField - Allow the ignored fieldnames to be configurable * plsql * [#3706](https://github.com/pmd/pmd/issues/3706): \[plsql] Parsing exception CURSOR statement with parenthesis groupings + * [#3687](https://github.com/pmd/pmd/issues/3687): \[plsql] Parsing exception EXECUTE IMMEDIATE l_sql BULK COLLECT INTO statement ### API Changes @@ -42,6 +43,7 @@ This is a {{ site.pmd.release_type }} release. * [#3883](https://github.com/pmd/pmd/pull/3883): \[doc] Improve side bar by Adding Release Date - [@jasonqiu98](https://github.com/jasonqiu98) * [#3910](https://github.com/pmd/pmd/pull/3910): \[java] UnusedPrivateField - Allow the ignored fieldnames to be configurable - [@laoseth](https://github.com/laoseth) * [#3928](https://github.com/pmd/pmd/pull/3928): \[plsql] Fix plsql parsing error in parenthesis groups - [@LiGaOg](https://github.com/LiGaOg) +* [#3935](https://github.com/pmd/pmd/pull/3935): \[plsql] Fix parser exception in EXECUTE IMMEDIATE BULK COLLECT #3687 - [@Scrsloota](https://github.com/Scrsloota) {% endtocmaker %} From f48ab0e5099bb7186475856a37981b030cf272b8 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 28 Apr 2022 11:57:30 +0200 Subject: [PATCH 148/180] [doc] Mark package n.s.p.lang.html experimental --- docs/pages/release_notes.md | 13 +++++++++++++ .../net/sourceforge/pmd/lang/html/package-info.java | 6 ++++++ 2 files changed, 19 insertions(+) create mode 100644 pmd-html/src/main/java/net/sourceforge/pmd/lang/html/package-info.java diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index e637b652d1..2b993593cb 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -18,6 +18,14 @@ This is a {{ site.pmd.release_type }} release. This version of PMD ships a new language module to support analyzing of HTML. Support for HTML is experimental and might change without notice. +The language implementation is not complete yet and the AST doesn't look +well for text nodes and comment nodes and might be changed in the future. +You can write your own rules, but we don't guarantee that the rules work with +the next (minor) version of PMD without adjustments. + +Please give us feedback about how practical this new language is in +[discussions](https://github.com/pmd/pmd/discussions). Please report +missing features or bugs as new [issues](https://github.com/pmd/pmd/issues). #### New rules @@ -68,6 +76,11 @@ Support for HTML is experimental and might change without notice. ### API Changes +#### Experimental APIs + +* The module `pmd-html` is entirely experimental right now. Anything in the package + `net.sourceforge.pmd.lang.html` should be used cautiously. + ### External Contributions * [#3883](https://github.com/pmd/pmd/pull/3883): \[doc] Improve side bar by Adding Release Date - [@jasonqiu98](https://github.com/jasonqiu98) * [#3910](https://github.com/pmd/pmd/pull/3910): \[java] UnusedPrivateField - Allow the ignored fieldnames to be configurable - [@laoseth](https://github.com/laoseth) diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/package-info.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/package-info.java new file mode 100644 index 0000000000..72286a3ccb --- /dev/null +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/package-info.java @@ -0,0 +1,6 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +@net.sourceforge.pmd.annotation.Experimental +package net.sourceforge.pmd.lang.html; From 56cc599b919f39eec28894ddc5efbdbd163b83f4 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 28 Apr 2022 12:11:08 +0200 Subject: [PATCH 149/180] Update pmd-core/src/main/java/net/sourceforge/pmd/Report.java MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Clément Fournier --- pmd-core/src/main/java/net/sourceforge/pmd/Report.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/Report.java b/pmd-core/src/main/java/net/sourceforge/pmd/Report.java index 40dd28177c..4ae30ee948 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/Report.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/Report.java @@ -38,7 +38,7 @@ import net.sourceforge.pmd.util.Predicate; * internalized in PMD 7. * *

For special use cases, like filtering the report after PMD analysis and - * before rendering the report, some limited mutating operations are provided: + * before rendering the report, some transformation operations are provided: *

    *
  • {@link #filterViolations(Predicate)}
  • *
  • {@link #union(Report)}
  • From 0af388360783424968c83cef233dcd3b8629d3b8 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 28 Apr 2022 15:00:55 +0200 Subject: [PATCH 150/180] [doc] Update release notes (#3603, #3938) --- 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 962f226a13..3c1aa11a75 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -31,6 +31,7 @@ This is a {{ site.pmd.release_type }} release. * [#2505](https://github.com/pmd/pmd/issues/2505): \[doc] Improve side bar to show release date * java * [#3068](https://github.com/pmd/pmd/issues/3068): \[java] Some tests should not depend on real rules + * [#3603](https://github.com/pmd/pmd/issues/3603): \[java] SimplifiedTernary: no violation for 'condition ? true : false' case * [#3889](https://github.com/pmd/pmd/pull/3889): \[java] Catch LinkageError in UselessOverridingMethodRule * [#3910](https://github.com/pmd/pmd/pull/3910): \[java] UnusedPrivateField - Allow the ignored fieldnames to be configurable * plsql @@ -42,6 +43,7 @@ This is a {{ site.pmd.release_type }} release. * [#3883](https://github.com/pmd/pmd/pull/3883): \[doc] Improve side bar by Adding Release Date - [@jasonqiu98](https://github.com/jasonqiu98) * [#3910](https://github.com/pmd/pmd/pull/3910): \[java] UnusedPrivateField - Allow the ignored fieldnames to be configurable - [@laoseth](https://github.com/laoseth) * [#3928](https://github.com/pmd/pmd/pull/3928): \[plsql] Fix plsql parsing error in parenthesis groups - [@LiGaOg](https://github.com/LiGaOg) +* [#3938](https://github.com/pmd/pmd/pull/3938): \[java] Modify SimplifiedTernary to meet the missing case #3603 - [@VoidxHoshi](https://github.com/VoidxHoshi) {% endtocmaker %} From d94f85f4437d0bc55c8723d9bfcc15033b7f10f3 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 28 Apr 2022 15:01:16 +0200 Subject: [PATCH 151/180] Add @VoidxHoshi as a contributor --- .all-contributorsrc | 9 ++ docs/pages/pmd/projectdocs/credits.md | 123 +++++++++++++------------- 2 files changed, 71 insertions(+), 61 deletions(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 4a058b2ad4..e957b1573d 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6612,6 +6612,15 @@ "contributions": [ "code" ] + }, + { + "login": "VoidxHoshi", + "name": "LaLucid", + "avatar_url": "https://avatars.githubusercontent.com/u/55886143?v=4", + "profile": "https://github.com/VoidxHoshi", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 7, diff --git a/docs/pages/pmd/projectdocs/credits.md b/docs/pages/pmd/projectdocs/credits.md index 6902116903..855f09edf4 100644 --- a/docs/pages/pmd/projectdocs/credits.md +++ b/docs/pages/pmd/projectdocs/credits.md @@ -395,552 +395,553 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
    Koen Van Looveren

    🐛
    Kris Scheibe

    💻 🐛
    Kunal Thanki

    🐛 +
    LaLucid

    💻
    Larry Diamond

    💻 🐛
    Lars Knickrehm

    🐛
    Leo Gutierrez

    🐛 -
    LiGaOg

    💻 +
    LiGaOg

    💻
    Lintsi

    🐛
    Linus Fernandes

    🐛
    Lixon Lookose

    🐛
    Logesh

    🐛
    Lorenzo Gabriele

    🐛
    Loïc Ledoyen

    🐛 -
    Lucas Silva

    🐛 +
    Lucas Silva

    🐛
    Lucas Soncini

    💻 🐛
    Lukasz Slonina

    🐛
    Lukebray

    🐛
    Lyor Goldstein

    🐛
    MCMicS

    🐛
    Macarse

    🐛 -
    Machine account for PMD

    💻 +
    Machine account for PMD

    💻
    Maciek Siemczyk

    🐛
    Maikel Steneker

    💻 🐛
    Maksim Moiseikin

    🐛
    Manfred Koch

    🐛
    Manuel Moya Ferrer

    💻 🐛
    Manuel Ryan

    🐛 -
    Marat Vyshegorodtsev

    🐛 +
    Marat Vyshegorodtsev

    🐛
    Marcel Härle

    🐛
    Marcello Fialho

    🐛
    Marcin Rataj

    🐛
    Mark Adamcin

    🐛
    Mark Hall

    💻 🐛
    Mark Kolich

    🐛 -
    Mark Pritchard

    🐛 +
    Mark Pritchard

    🐛
    Markus Rathgeb

    🐛
    Marquis Wang

    🐛
    Martin Feldsztejn

    🐛
    Martin Lehmann

    🐛
    Martin Spamer

    🐛
    Martin Tarjányi

    🐛 -
    MatFl

    🐛 +
    MatFl

    🐛
    Mateusz Stefanski

    🐛
    Mathieu Gouin

    🐛
    MatiasComercio

    💻 🐛
    Matt Benson

    🐛
    Matt De Poorter

    🐛
    Matt Harrah

    🐛 -
    Matt Nelson

    🐛 +
    Matt Nelson

    🐛
    Matthew Amos

    🐛
    Matthew Duggan

    🐛
    Matthew Hall

    🐛
    Matías Fraga

    💻 🐛
    Maxime Robert

    💻 🐛
    MetaBF

    🐛 -
    Michael

    🐛 +
    Michael

    🐛
    Michael Bell

    🐛
    Michael Bernstein

    🐛
    Michael Clay

    🐛
    Michael Dombrowski

    🐛
    Michael Hausegger

    🐛
    Michael Hoefer

    🐛 -
    Michael Möbius

    🐛 +
    Michael Möbius

    🐛
    Michael N. Lipp

    🐛
    Michael Pellegrini

    🐛
    Michal Kordas

    🐛
    Michał Borek

    🐛
    Michał Kuliński

    🐛
    Miguel Núñez Díaz-Montes

    🐛 -
    Mihai Ionut

    🐛 +
    Mihai Ionut

    🐛
    Mirek Hankus

    🐛
    Mladjan Gadzic

    🐛
    MrAngry52

    🐛
    Muminur Choudhury

    🐛
    Mykhailo Palahuta

    💻 🐛
    Nagendra Kumar Singh

    🐛 -
    Nahuel Barrios

    🐛 +
    Nahuel Barrios

    🐛
    Nathan Braun

    🐛
    Nathan Reynolds

    🐛
    Nathan Reynolds

    🐛
    Nathanaël

    🐛
    Nazdravi

    🐛
    Neha-Dhonde

    🐛 -
    Nicholas Doyle

    🐛 +
    Nicholas Doyle

    🐛
    Nick Butcher

    🐛
    Nico Gallinal

    🐛
    Nicola Dal Maso

    🐛
    Nicolas Filotto

    💻
    Nikita Chursin

    🐛
    Niklas Baudy

    🐛 -
    Nikolas Havrikov

    🐛 +
    Nikolas Havrikov

    🐛
    Nilesh Virkar

    🐛
    Nimit Patel

    🐛
    Niranjan Harpale

    🐛
    Noah Sussman

    🐛
    Noah0120

    🐛
    Noam Tamim

    🐛 -
    Noel Grandin

    🐛 +
    Noel Grandin

    🐛
    Olaf Haalstra

    🐛
    Oleg Pavlenko

    🐛
    Oleksii Dykov

    💻
    Oliver Eikemeier

    🐛
    Olivier Parent

    💻 🐛
    Ollie Abbey

    💻 🐛 -
    OverDrone

    🐛 +
    OverDrone

    🐛
    Ozan Gulle

    💻 🐛
    PUNEET JAIN

    🐛
    Parbati Bose

    🐛
    Paul Berg

    🐛
    Pavel Bludov

    🐛
    Pavel Mička

    🐛 -
    Pedro Nuno Santos

    🐛 +
    Pedro Nuno Santos

    🐛
    Pedro Rijo

    🐛
    Pelisse Romain

    💻 📖 🐛
    Pete Davids

    🐛
    Peter Bruin

    🐛
    Peter Chittum

    💻 🐛
    Peter Cudmore

    🐛 -
    Peter Kasson

    🐛 +
    Peter Kasson

    🐛
    Peter Kofler

    🐛
    Pham Hai Trung

    🐛
    Philip Graf

    💻 🐛
    Philip Hachey

    🐛
    Philippe Ozil

    🐛
    Phinehas Artemix

    🐛 -
    Phokham Nonava

    🐛 +
    Phokham Nonava

    🐛
    Piotr Szymański

    🐛
    Piotrek Żygieło

    💻 🐛
    Pranay Jaiswal

    🐛
    Prasad Kamath

    🐛
    Prasanna

    🐛
    Presh-AR

    🐛 -
    Puneet1726

    🐛 +
    Puneet1726

    🐛
    Rafael Cortês

    🐛
    RaheemShaik999

    🐛
    RajeshR

    💻 🐛
    Ramachandra Mohan

    🐛
    Raquel Pau

    🐛
    Ravikiran Janardhana

    🐛 -
    Reda Benhemmouche

    🐛 +
    Reda Benhemmouche

    🐛
    Renato Oliveira

    💻 🐛
    Rich DiCroce

    🐛
    Riot R1cket

    🐛
    Rishabh Jain

    🐛
    RishabhDeep Singh

    🐛
    Robbie Martinus

    💻 🐛 -
    Robert Henry

    🐛 +
    Robert Henry

    🐛
    Robert Painsi

    🐛
    Robert Russell

    🐛
    Robert Sösemann

    💻 📖 📢 🐛
    Robert Whitebit

    🐛
    Robin Richtsfeld

    🐛
    Robin Stocker

    💻 🐛 -
    Robin Wils

    🐛 +
    Robin Wils

    🐛
    RochusOest

    🐛
    Rodolfo Noviski

    🐛
    Rodrigo Casara

    🐛
    Rodrigo Fernandes

    🐛
    Roman Salvador

    💻 🐛
    Ronald Blaschke

    🐛 -
    Róbert Papp

    🐛 +
    Róbert Papp

    🐛
    Saikat Sengupta

    🐛
    Saksham Handu

    🐛
    Saladoc

    🐛
    Salesforce Bob Lightning

    🐛
    Sam Carlberg

    🐛
    Satoshi Kubo

    🐛 -
    Scott Kennedy

    🐛 +
    Scott Kennedy

    🐛
    Scott Wells

    🐛 💻
    Sebastian Bögl

    🐛
    Sebastian Schuberth

    🐛
    Sebastian Schwarz

    🐛
    Sergey Gorbaty

    🐛
    Sergey Kozlov

    🐛 -
    Sergey Yanzin

    💻 🐛 +
    Sergey Yanzin

    💻 🐛
    Seth Wilcox

    💻
    Shubham

    💻 🐛
    Simon Xiao

    🐛
    Srinivasan Venkatachalam

    🐛
    Stanislav Gromov

    🐛
    Stanislav Myachenkov

    💻 -
    Stefan Birkner

    🐛 +
    Stefan Birkner

    🐛
    Stefan Bohn

    🐛
    Stefan Endrullis

    🐛
    Stefan Klöss-Schuster

    🐛
    Stefan Wolf

    🐛
    Stephan H. Wissel

    🐛
    Stephen

    🐛 -
    Stephen Friedrich

    🐛 +
    Stephen Friedrich

    🐛
    Steve Babula

    💻
    Stexxe

    🐛
    Stian Lågstad

    🐛
    StuartClayton5

    🐛
    Supun Arunoda

    🐛
    Suren Abrahamyan

    🐛 -
    SwatiBGupta1110

    🐛 +
    SwatiBGupta1110

    🐛
    SyedThoufich

    🐛
    Szymon Sasin

    🐛
    T-chuangxin

    🐛
    TERAI Atsuhiro

    🐛
    TIOBE Software

    💻 🐛
    Taylor Smock

    🐛 -
    Techeira Damián

    💻 🐛 +
    Techeira Damián

    💻 🐛
    Ted Husted

    🐛
    TehBakker

    🐛
    The Gitter Badger

    🐛
    Theodoor

    🐛
    Thiago Henrique Hüpner

    🐛
    Thibault Meyer

    🐛 -
    Thomas Güttler

    🐛 +
    Thomas Güttler

    🐛
    Thomas Jones-Low

    🐛
    Thomas Smith

    💻 🐛
    ThrawnCA

    🐛
    Thunderforge

    💻 🐛
    Tim van der Lippe

    🐛
    Tobias Weimer

    💻 🐛 -
    Tom Daly

    🐛 +
    Tom Daly

    🐛
    Tomer Figenblat

    🐛
    Tomi De Lucca

    💻 🐛
    Torsten Kleiber

    🐛
    TrackerSB

    🐛
    Ullrich Hafner

    🐛
    Utku Cuhadaroglu

    💻 🐛 -
    Valentin Brandl

    🐛 +
    Valentin Brandl

    🐛
    Valeria

    🐛
    Vasily Anisimov

    🐛
    Vickenty Fesunov

    🐛
    Victor Noël

    🐛
    Vincent Galloy

    💻
    Vincent HUYNH

    🐛 -
    Vincent Maurin

    🐛 +
    Vincent Maurin

    🐛
    Vincent Privat

    🐛
    Vishhwas

    🐛
    Vitaly

    🐛
    Vitaly Polonetsky

    🐛
    Vojtech Polivka

    🐛
    Vsevolod Zholobov

    🐛 -
    Vyom Yadav

    💻 +
    Vyom Yadav

    💻
    Wang Shidong

    🐛
    Waqas Ahmed

    🐛
    Wayne J. Earl

    🐛
    Wchenghui

    🐛
    Will Winder

    🐛
    William Brockhus

    💻 🐛 -
    Wilson Kurniawan

    🐛 +
    Wilson Kurniawan

    🐛
    Wim Deblauwe

    🐛
    Woongsik Choi

    🐛
    XenoAmess

    💻 🐛
    Yang

    💻
    YaroslavTER

    🐛
    Young Chan

    💻 🐛 -
    YuJin Kim

    🐛 +
    YuJin Kim

    🐛
    Yuri Dolzhenko

    🐛
    Yurii Dubinka

    🐛
    Zoltan Farkas

    🐛
    Zustin

    🐛
    aaronhurst-google

    🐛
    alexmodis

    🐛 -
    andreoss

    🐛 +
    andreoss

    🐛
    andrey81inmd

    💻 🐛
    anicoara

    🐛
    arunprasathav

    🐛
    asiercamara

    🐛
    astillich-igniti

    💻
    avesolovksyy

    🐛 -
    avishvat

    🐛 +
    avishvat

    🐛
    avivmu

    🐛
    axelbarfod1

    🐛
    b-3-n

    🐛
    balbhadra9

    🐛
    base23de

    🐛
    bergander

    🐛 -
    berkam

    💻 🐛 +
    berkam

    💻 🐛
    breizh31

    🐛
    caesarkim

    🐛
    carolyujing

    🐛
    cesares-basilico

    🐛
    chrite

    🐛
    cobratbq

    🐛 -
    coladict

    🐛 +
    coladict

    🐛
    cosmoJFH

    🐛
    cristalp

    🐛
    crunsk

    🐛
    cwholmes

    🐛
    cyberjj999

    🐛
    cyw3

    🐛 -
    d1ss0nanz

    🐛 +
    d1ss0nanz

    🐛
    danbrycefairsailcom

    🐛
    dariansanity

    🐛
    darrenmiliband

    🐛
    davidburstrom

    🐛
    dbirkman-paloalto

    🐛
    deepak-patra

    🐛 -
    dependabot[bot]

    💻 🐛 +
    dependabot[bot]

    💻 🐛
    dinesh150

    🐛
    diziaq

    🐛
    dreaminpast123

    🐛
    duanyanan

    🐛
    dutt-sanjay

    🐛
    dylanleung

    🐛 -
    dzeigler

    🐛 +
    dzeigler

    🐛
    ekkirala

    🐛
    emersonmoura

    🐛
    fairy

    🐛
    filiprafalowicz

    💻
    foxmason

    🐛
    frankegabor

    🐛 -
    frankl

    🐛 +
    frankl

    🐛
    freafrea

    🐛
    fsapatin

    🐛
    gracia19

    🐛
    guo fei

    🐛
    gurmsc5

    🐛
    gwilymatgearset

    💻 🐛 -
    haigsn

    🐛 +
    haigsn

    🐛
    hemanshu070

    🐛
    henrik242

    🐛
    hongpuwu

    🐛
    hvbtup

    💻 🐛
    igniti GmbH

    🐛
    ilovezfs

    🐛 -
    itaigilo

    🐛 +
    itaigilo

    🐛
    jakivey32

    🐛
    jbennett2091

    🐛
    jcamerin

    🐛
    jkeener1

    🐛
    jmetertea

    🐛
    johnra2

    💻 -
    josemanuelrolon

    💻 🐛 +
    josemanuelrolon

    💻 🐛
    kabroxiko

    💻 🐛
    karwer

    🐛
    kaulonline

    🐛
    kdaemonv

    🐛
    kenji21

    💻 🐛
    kfranic

    🐛 -
    khalidkh

    🐛 +
    khalidkh

    🐛
    krzyk

    🐛
    lasselindqvist

    🐛
    lihuaib

    🐛
    lonelyma1021

    🐛
    lpeddy

    🐛
    lujiefsi

    💻 -
    lyriccoder

    🐛 +
    lyriccoder

    🐛
    marcelmore

    🐛
    matchbox

    🐛
    matthiaskraaz

    🐛
    meandonlyme

    🐛
    mikesive

    🐛
    milossesic

    🐛 -
    mriddell95

    🐛 +
    mriddell95

    🐛
    mrlzh

    🐛
    msloan

    🐛
    mucharlaravalika

    🐛
    mvenneman

    🐛
    nareshl119

    🐛
    nicolas-harraudeau-sonarsource

    🐛 -
    noerremark

    🐛 +
    noerremark

    🐛
    novsirion

    🐛
    oggboy

    🐛
    oinume

    🐛
    orimarko

    💻 🐛
    pallavi agarwal

    🐛
    parksungrin

    🐛 -
    patpatpat123

    🐛 +
    patpatpat123

    🐛
    patriksevallius

    🐛
    pbrajesh1

    🐛
    phoenix384

    🐛
    piotrszymanski-sc

    💻
    plan3d

    🐛
    poojasix

    🐛 -
    prabhushrikant

    🐛 +
    prabhushrikant

    🐛
    pujitha8783

    🐛
    r-r-a-j

    🐛
    raghujayjunk

    🐛
    rajeshveera

    🐛
    rajeswarreddy88

    🐛
    recdevs

    🐛 -
    reudismam

    💻 🐛 +
    reudismam

    💻 🐛
    rijkt

    🐛
    rillig-tk

    🐛
    rmohan20

    💻 🐛
    rxmicro

    🐛
    ryan-gustafson

    💻 🐛
    sabi0

    🐛 -
    scais

    🐛 +
    scais

    🐛
    sebbASF

    🐛
    sergeygorbaty

    💻
    shilko2013

    🐛
    simeonKondr

    🐛
    snajberk

    🐛
    sniperrifle2004

    🐛 -
    snuyanzin

    🐛 💻 +
    snuyanzin

    🐛 💻
    sratz

    🐛
    stonio

    🐛
    sturton

    💻 🐛
    sudharmohan

    🐛
    suruchidawar

    🐛
    svenfinitiv

    🐛 -
    tashiscool

    🐛 +
    tashiscool

    🐛
    test-git-hook

    🐛
    testation21

    💻 🐛
    thanosa

    🐛
    tiandiyixian

    🐛
    tobwoerk

    🐛
    tprouvot

    🐛 -
    trentchilders

    🐛 +
    trentchilders

    🐛
    triandicAnt

    🐛
    trishul14

    🐛
    tsui

    🐛
    winhkey

    🐛
    witherspore

    🐛
    wjljack

    🐛 -
    wuchiuwong

    🐛 +
    wuchiuwong

    🐛
    xingsong

    🐛
    xioayuge

    🐛
    xnYi9wRezm

    💻 🐛
    xuanuy

    🐛
    xyf0921

    🐛
    yalechen-cyw3

    🐛 -
    yasuharu-sato

    🐛 +
    yasuharu-sato

    🐛
    zenglian

    🐛
    zgrzyt93

    💻 🐛
    zh3ng

    🐛
    zt_soft

    🐛
    ztt79

    🐛
    zzzzfeng

    🐛 -
    Árpád Magosányi

    🐛 +
    Árpád Magosányi

    🐛
    任贵杰

    🐛 From 3336b1ccd4dba81fc63385375c78a425cc498f3c Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 28 Apr 2022 15:05:26 +0200 Subject: [PATCH 152/180] [doc] Update release notes --- docs/pages/release_notes.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 400d774f08..b97f2a6c0f 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -32,19 +32,20 @@ This is a {{ site.pmd.release_type }} release. * [#2505](https://github.com/pmd/pmd/issues/2505): \[doc] Improve side bar to show release date * java * [#3068](https://github.com/pmd/pmd/issues/3068): \[java] Some tests should not depend on real rules - * [#3603](https://github.com/pmd/pmd/issues/3603): \[java] SimplifiedTernary: no violation for 'condition ? true : false' case * [#3889](https://github.com/pmd/pmd/pull/3889): \[java] Catch LinkageError in UselessOverridingMethodRule - * [#3910](https://github.com/pmd/pmd/pull/3910): \[java] UnusedPrivateField - Allow the ignored fieldnames to be configurable * java-bestpractices + * [#3910](https://github.com/pmd/pmd/pull/3910): \[java] UnusedPrivateField - Allow the ignored fieldnames to be configurable * [#1185](https://github.com/pmd/pmd/issues/1185): \[java] ArrayIsStoredDirectly false positive with field access * [#1474](https://github.com/pmd/pmd/issues/1474): \[java] ArrayIsStoredDirectly false positive with method call * [#3879](https://github.com/pmd/pmd/issues/3879) \[java] ArrayIsStoredDirectly reports duplicated violation * [#3929](https://github.com/pmd/pmd/issues/3929): \[java] ArrayIsStoredDirectly should report the assignment rather than formal parameter +* java-design + * [#3603](https://github.com/pmd/pmd/issues/3603): \[java] SimplifiedTernary: no violation for 'condition ? true : false' case * java-performance * [#3867](https://github.com/pmd/pmd/issues/3867): \[java] UseArraysAsList with method call * plsql - * [#3706](https://github.com/pmd/pmd/issues/3706): \[plsql] Parsing exception CURSOR statement with parenthesis groupings * [#3687](https://github.com/pmd/pmd/issues/3687): \[plsql] Parsing exception EXECUTE IMMEDIATE l_sql BULK COLLECT INTO statement + * [#3706](https://github.com/pmd/pmd/issues/3706): \[plsql] Parsing exception CURSOR statement with parenthesis groupings ### API Changes From 73f670b11a9110de581a10c4763929a5b046cdd4 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 28 Apr 2022 16:00:53 +0200 Subject: [PATCH 153/180] [plsql] Fix compile and test errors --- .../ast/ExecuteImmediateBulkCollectTest.java | 2 +- .../ast/ExecuteImmediateBulkCollect1.txt | 43 ++---- .../ast/ExecuteImmediateBulkCollect2.txt | 146 +++++++----------- .../ast/ExecuteImmediateBulkCollect3.txt | 113 ++++++-------- 4 files changed, 115 insertions(+), 189 deletions(-) diff --git a/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollectTest.java b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollectTest.java index 63982ea168..0d06ef1c5f 100644 --- a/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollectTest.java +++ b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollectTest.java @@ -19,7 +19,7 @@ public class ExecuteImmediateBulkCollectTest extends BaseTreeDumpTest { @Override public BaseParsingHelper getParser() { - return PlsqlParsingHelper.WITH_PROCESSING.withResourceContext(getClass()); + return PlsqlParsingHelper.DEFAULT.withResourceContext(getClass()); } @Test diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect1.txt b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect1.txt index 6c18018e50..64026947bf 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect1.txt +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect1.txt @@ -1,26 +1,7 @@ -+- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0, @Sourcecode = "-- --- BSD-style license; for more info see http://pmd.sourceforge.net/license.html --- - -CREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS - -- - TYPE t_data IS TABLE OF dual%ROWTYPE INDEX BY BINARY_INTEGER; - -- - l_data t_data; - l_sql VARCHAR2(500); - -- -BEGIN - -- - l_sql := 'SELECT * FROM DUAL'; - -- - EXECUTE IMMEDIATE l_sql BULK COLLECT - INTO l_data; - -- -END EXAMPLE_PROCEDURE; -"] ++- Input[@CanonicalImage = null, @ExcludedLinesCount = "0", @ExcludedRangesCount = "0", @Sourcecode = "--\n-- BSD-style license; for more info see http://pmd.sourceforge.net/license.html\n--\n\nCREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS\n --\n TYPE t_data IS TABLE OF dual%ROWTYPE INDEX BY BINARY_INTEGER;\n --\n l_data t_data;\n l_sql VARCHAR2(500);\n --\nBEGIN\n --\n l_sql := \'SELECT * FROM DUAL\';\n --\n EXECUTE IMMEDIATE l_sql BULK COLLECT\n INTO l_data;\n --\nEND EXAMPLE_PROCEDURE;\n"] +- Global[@CanonicalImage = null] +- ProgramUnit[@CanonicalImage = null, @MethodName = "EXAMPLE_PROCEDURE", @Name = "EXAMPLE_PROCEDURE", @ObjectName = null] - +- MethodDeclarator[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE", @ParameterCount = 1] + +- MethodDeclarator[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE", @ParameterCount = "1"] | +- ObjectNameDeclaration[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE"] | +- ID[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE"] +- DeclarativeSection[@CanonicalImage = null] @@ -35,7 +16,7 @@ END EXAMPLE_PROCEDURE; | +- DeclarativeUnit[@CanonicalImage = null] | | +- VariableOrConstantDeclaration[@CanonicalImage = null] | | +- VariableOrConstantDeclarator[@CanonicalImage = "L_DATA T_DATA", @Image = "l_data t_data"] - | | +- VariableOrConstantDeclaratorId[@Array = false, @ArrayDepth = 0, @CanonicalImage = "L_DATA", @Image = "l_data"] + | | +- VariableOrConstantDeclaratorId[@Array = "false", @ArrayDepth = "0", @CanonicalImage = "L_DATA", @Image = "l_data"] | | | +- ID[@CanonicalImage = "L_DATA", @Image = "l_data"] | | +- Datatype[@CanonicalImage = "T_DATA", @Image = "t_data", @TypeImage = "t_data"] | | +- QualifiedName[@CanonicalImage = "T_DATA", @Image = "t_data"] @@ -43,28 +24,28 @@ END EXAMPLE_PROCEDURE; | +- DeclarativeUnit[@CanonicalImage = null] | +- VariableOrConstantDeclaration[@CanonicalImage = null] | +- VariableOrConstantDeclarator[@CanonicalImage = "L_SQL VARCHAR2(500)", @Image = "l_sql VARCHAR2(500)"] - | +- VariableOrConstantDeclaratorId[@Array = false, @ArrayDepth = 0, @CanonicalImage = "L_SQL", @Image = "l_sql"] + | +- VariableOrConstantDeclaratorId[@Array = "false", @ArrayDepth = "0", @CanonicalImage = "L_SQL", @Image = "l_sql"] | | +- ID[@CanonicalImage = "L_SQL", @Image = "l_sql"] | +- Datatype[@CanonicalImage = "VARCHAR2(500)", @Image = "VARCHAR2(500)", @TypeImage = "VARCHAR2(500)"] | +- ScalarDataTypeName[@CanonicalImage = "VARCHAR2(500)", @Image = "VARCHAR2(500)"] | +- NumericLiteral[@CanonicalImage = "500", @Image = "500"] +- Statement[@CanonicalImage = null] | +- UnlabelledStatement[@CanonicalImage = null] - | +- Expression[@CanonicalImage = "L_SQL := 'SELECT * FROM DUAL'", @Image = "l_sql := 'SELECT * FROM DUAL'"] - | +- Assignment[@CanonicalImage = "L_SQL := 'SELECT * FROM DUAL'", @Image = "l_sql := 'SELECT * FROM DUAL'"] - | +- PrimaryPrefix[@CanonicalImage = "L_SQL", @Image = "l_sql", @SelfModifier = false] + | +- Expression[@CanonicalImage = "L_SQL := \'SELECT * FROM DUAL\'", @Image = "l_sql := \'SELECT * FROM DUAL\'"] + | +- Assignment[@CanonicalImage = "L_SQL := \'SELECT * FROM DUAL\'", @Image = "l_sql := \'SELECT * FROM DUAL\'"] + | +- PrimaryPrefix[@CanonicalImage = "L_SQL", @Image = "l_sql", @SelfModifier = "false"] | | +- SimpleExpression[@CanonicalImage = "L_SQL", @Image = "l_sql"] | | +- Column[@CanonicalImage = "L_SQL", @Image = "l_sql"] | | +- ID[@CanonicalImage = "L_SQL", @Image = "l_sql"] - | +- Expression[@CanonicalImage = "'SELECT * FROM DUAL'", @Image = "'SELECT * FROM DUAL'"] - | +- PrimaryPrefix[@CanonicalImage = "'SELECT * FROM DUAL'", @Image = "'SELECT * FROM DUAL'", @SelfModifier = false] - | +- Literal[@CanonicalImage = "'SELECT * FROM DUAL'", @Image = "'SELECT * FROM DUAL'"] - | +- StringLiteral[@CanonicalImage = "'SELECT * FROM DUAL'", @Image = "'SELECT * FROM DUAL'", @String = "SELECT * FROM DUAL"] + | +- Expression[@CanonicalImage = "\'SELECT * FROM DUAL\'", @Image = "\'SELECT * FROM DUAL\'"] + | +- PrimaryPrefix[@CanonicalImage = "\'SELECT * FROM DUAL\'", @Image = "\'SELECT * FROM DUAL\'", @SelfModifier = "false"] + | +- Literal[@CanonicalImage = "\'SELECT * FROM DUAL\'", @Image = "\'SELECT * FROM DUAL\'"] + | +- StringLiteral[@CanonicalImage = "\'SELECT * FROM DUAL\'", @Image = "\'SELECT * FROM DUAL\'", @String = "SELECT * FROM DUAL"] +- Statement[@CanonicalImage = null] | +- UnlabelledStatement[@CanonicalImage = null] | +- EmbeddedSqlStatement[@CanonicalImage = null] | +- StringExpression[@CanonicalImage = "L_SQL", @Image = "l_sql"] - | | +- PrimaryPrefix[@CanonicalImage = "L_SQL", @Image = "l_sql", @SelfModifier = false] + | | +- PrimaryPrefix[@CanonicalImage = "L_SQL", @Image = "l_sql", @SelfModifier = "false"] | | +- SimpleExpression[@CanonicalImage = "L_SQL", @Image = "l_sql"] | | +- Column[@CanonicalImage = "L_SQL", @Image = "l_sql"] | | +- ID[@CanonicalImage = "L_SQL", @Image = "l_sql"] diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect2.txt b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect2.txt index 379336f71f..a5e2758937 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect2.txt +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect2.txt @@ -1,37 +1,7 @@ -+- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0, @Sourcecode = "-- --- BSD-style license; for more info see http://pmd.sourceforge.net/license.html --- - -CREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS - -- - TYPE t_data_key IS TABLE OF NUMBER INDEX BY BINARY_INTEGER; - TYPE t_data_description IS TABLE OF VARCHAR2(100) INDEX BY BINARY_INTEGER; - -- - l_data_key t_data_key; - l_data_description t_data_description; - l_sql VARCHAR2(500); - p_rownum1 NUMBER(20); - p_rownum2 NUMBER(20); - -- -BEGIN - -- - p_rownum1 := 10; - p_rownum2 := 30; - -- - l_sql := 'SELECT 1, ' || CHR(39) || 'First key' || CHR(39) || - ' FROM DUAL '||' WHERE ROWNUM <= :p_rownum1 ' || - 'UNION ALL '|| - 'SELECT 2, ' || CHR(39) || 'Second key ' || CHR(39) || - ' FROM DUAL'||' WHERE ROWNUM <= :p_rownum2 '; - -- - EXECUTE IMMEDIATE l_sql BULK COLLECT - INTO l_data_key, l_data_description USING p_rownum1, p_rownum2; - -- -END EXAMPLE_PROCEDURE; -"] ++- Input[@CanonicalImage = null, @ExcludedLinesCount = "0", @ExcludedRangesCount = "0", @Sourcecode = "--\n-- BSD-style license; for more info see http://pmd.sourceforge.net/license.html\n--\n\nCREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS\n --\n TYPE t_data_key IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;\n TYPE t_data_description IS TABLE OF VARCHAR2(100) INDEX BY BINARY_INTEGER;\n --\n l_data_key t_data_key;\n l_data_description t_data_description;\n l_sql VARCHAR2(500);\n p_rownum1 NUMBER(20);\n p_rownum2 NUMBER(20);\n --\nBEGIN\n --\n p_rownum1 := 10;\n p_rownum2 := 30;\n --\n l_sql := \'SELECT 1, \' || CHR(39) || \'First key\' || CHR(39) || \n \' FROM DUAL \'||\' WHERE ROWNUM <= :p_rownum1 \' ||\n \'UNION ALL \'||\n \'SELECT 2, \' || CHR(39) || \'Second key \' || CHR(39) || \n \' FROM DUAL\'||\' WHERE ROWNUM <= :p_rownum2 \';\n --\n EXECUTE IMMEDIATE l_sql BULK COLLECT\n INTO l_data_key, l_data_description USING p_rownum1, p_rownum2;\n --\nEND EXAMPLE_PROCEDURE;\n"] +- Global[@CanonicalImage = null] +- ProgramUnit[@CanonicalImage = null, @MethodName = "EXAMPLE_PROCEDURE", @Name = "EXAMPLE_PROCEDURE", @ObjectName = null] - +- MethodDeclarator[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE", @ParameterCount = 1] + +- MethodDeclarator[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE", @ParameterCount = "1"] | +- ObjectNameDeclaration[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE"] | +- ID[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE"] +- DeclarativeSection[@CanonicalImage = null] @@ -53,7 +23,7 @@ END EXAMPLE_PROCEDURE; | +- DeclarativeUnit[@CanonicalImage = null] | | +- VariableOrConstantDeclaration[@CanonicalImage = null] | | +- VariableOrConstantDeclarator[@CanonicalImage = "L_DATA_KEY T_DATA_KEY", @Image = "l_data_key t_data_key"] - | | +- VariableOrConstantDeclaratorId[@Array = false, @ArrayDepth = 0, @CanonicalImage = "L_DATA_KEY", @Image = "l_data_key"] + | | +- VariableOrConstantDeclaratorId[@Array = "false", @ArrayDepth = "0", @CanonicalImage = "L_DATA_KEY", @Image = "l_data_key"] | | | +- ID[@CanonicalImage = "L_DATA_KEY", @Image = "l_data_key"] | | +- Datatype[@CanonicalImage = "T_DATA_KEY", @Image = "t_data_key", @TypeImage = "t_data_key"] | | +- QualifiedName[@CanonicalImage = "T_DATA_KEY", @Image = "t_data_key"] @@ -61,7 +31,7 @@ END EXAMPLE_PROCEDURE; | +- DeclarativeUnit[@CanonicalImage = null] | | +- VariableOrConstantDeclaration[@CanonicalImage = null] | | +- VariableOrConstantDeclarator[@CanonicalImage = "L_DATA_DESCRIPTION T_DATA_DESCRIPTION", @Image = "l_data_description t_data_description"] - | | +- VariableOrConstantDeclaratorId[@Array = false, @ArrayDepth = 0, @CanonicalImage = "L_DATA_DESCRIPTION", @Image = "l_data_description"] + | | +- VariableOrConstantDeclaratorId[@Array = "false", @ArrayDepth = "0", @CanonicalImage = "L_DATA_DESCRIPTION", @Image = "l_data_description"] | | | +- ID[@CanonicalImage = "L_DATA_DESCRIPTION", @Image = "l_data_description"] | | +- Datatype[@CanonicalImage = "T_DATA_DESCRIPTION", @Image = "t_data_description", @TypeImage = "t_data_description"] | | +- QualifiedName[@CanonicalImage = "T_DATA_DESCRIPTION", @Image = "t_data_description"] @@ -69,7 +39,7 @@ END EXAMPLE_PROCEDURE; | +- DeclarativeUnit[@CanonicalImage = null] | | +- VariableOrConstantDeclaration[@CanonicalImage = null] | | +- VariableOrConstantDeclarator[@CanonicalImage = "L_SQL VARCHAR2(500)", @Image = "l_sql VARCHAR2(500)"] - | | +- VariableOrConstantDeclaratorId[@Array = false, @ArrayDepth = 0, @CanonicalImage = "L_SQL", @Image = "l_sql"] + | | +- VariableOrConstantDeclaratorId[@Array = "false", @ArrayDepth = "0", @CanonicalImage = "L_SQL", @Image = "l_sql"] | | | +- ID[@CanonicalImage = "L_SQL", @Image = "l_sql"] | | +- Datatype[@CanonicalImage = "VARCHAR2(500)", @Image = "VARCHAR2(500)", @TypeImage = "VARCHAR2(500)"] | | +- ScalarDataTypeName[@CanonicalImage = "VARCHAR2(500)", @Image = "VARCHAR2(500)"] @@ -77,7 +47,7 @@ END EXAMPLE_PROCEDURE; | +- DeclarativeUnit[@CanonicalImage = null] | | +- VariableOrConstantDeclaration[@CanonicalImage = null] | | +- VariableOrConstantDeclarator[@CanonicalImage = "P_ROWNUM1 NUMBER(20)", @Image = "p_rownum1 NUMBER(20)"] - | | +- VariableOrConstantDeclaratorId[@Array = false, @ArrayDepth = 0, @CanonicalImage = "P_ROWNUM1", @Image = "p_rownum1"] + | | +- VariableOrConstantDeclaratorId[@Array = "false", @ArrayDepth = "0", @CanonicalImage = "P_ROWNUM1", @Image = "p_rownum1"] | | | +- ID[@CanonicalImage = "P_ROWNUM1", @Image = "p_rownum1"] | | +- Datatype[@CanonicalImage = "NUMBER(20)", @Image = "NUMBER(20)", @TypeImage = "NUMBER(20)"] | | +- ScalarDataTypeName[@CanonicalImage = "NUMBER(20)", @Image = "NUMBER(20)"] @@ -85,7 +55,7 @@ END EXAMPLE_PROCEDURE; | +- DeclarativeUnit[@CanonicalImage = null] | +- VariableOrConstantDeclaration[@CanonicalImage = null] | +- VariableOrConstantDeclarator[@CanonicalImage = "P_ROWNUM2 NUMBER(20)", @Image = "p_rownum2 NUMBER(20)"] - | +- VariableOrConstantDeclaratorId[@Array = false, @ArrayDepth = 0, @CanonicalImage = "P_ROWNUM2", @Image = "p_rownum2"] + | +- VariableOrConstantDeclaratorId[@Array = "false", @ArrayDepth = "0", @CanonicalImage = "P_ROWNUM2", @Image = "p_rownum2"] | | +- ID[@CanonicalImage = "P_ROWNUM2", @Image = "p_rownum2"] | +- Datatype[@CanonicalImage = "NUMBER(20)", @Image = "NUMBER(20)", @TypeImage = "NUMBER(20)"] | +- ScalarDataTypeName[@CanonicalImage = "NUMBER(20)", @Image = "NUMBER(20)"] @@ -94,112 +64,112 @@ END EXAMPLE_PROCEDURE; | +- UnlabelledStatement[@CanonicalImage = null] | +- Expression[@CanonicalImage = "P_ROWNUM1 := 10", @Image = "p_rownum1 := 10"] | +- Assignment[@CanonicalImage = "P_ROWNUM1 := 10", @Image = "p_rownum1 := 10"] - | +- PrimaryPrefix[@CanonicalImage = "P_ROWNUM1", @Image = "p_rownum1", @SelfModifier = false] + | +- PrimaryPrefix[@CanonicalImage = "P_ROWNUM1", @Image = "p_rownum1", @SelfModifier = "false"] | | +- SimpleExpression[@CanonicalImage = "P_ROWNUM1", @Image = "p_rownum1"] | | +- Column[@CanonicalImage = "P_ROWNUM1", @Image = "p_rownum1"] | | +- ID[@CanonicalImage = "P_ROWNUM1", @Image = "p_rownum1"] | +- Expression[@CanonicalImage = "10", @Image = "10"] - | +- PrimaryPrefix[@CanonicalImage = "10", @Image = "10", @SelfModifier = false] + | +- PrimaryPrefix[@CanonicalImage = "10", @Image = "10", @SelfModifier = "false"] | +- Literal[@CanonicalImage = "10", @Image = "10"] | +- NumericLiteral[@CanonicalImage = "10", @Image = "10"] +- Statement[@CanonicalImage = null] | +- UnlabelledStatement[@CanonicalImage = null] | +- Expression[@CanonicalImage = "P_ROWNUM2 := 30", @Image = "p_rownum2 := 30"] | +- Assignment[@CanonicalImage = "P_ROWNUM2 := 30", @Image = "p_rownum2 := 30"] - | +- PrimaryPrefix[@CanonicalImage = "P_ROWNUM2", @Image = "p_rownum2", @SelfModifier = false] + | +- PrimaryPrefix[@CanonicalImage = "P_ROWNUM2", @Image = "p_rownum2", @SelfModifier = "false"] | | +- SimpleExpression[@CanonicalImage = "P_ROWNUM2", @Image = "p_rownum2"] | | +- Column[@CanonicalImage = "P_ROWNUM2", @Image = "p_rownum2"] | | +- ID[@CanonicalImage = "P_ROWNUM2", @Image = "p_rownum2"] | +- Expression[@CanonicalImage = "30", @Image = "30"] - | +- PrimaryPrefix[@CanonicalImage = "30", @Image = "30", @SelfModifier = false] + | +- PrimaryPrefix[@CanonicalImage = "30", @Image = "30", @SelfModifier = "false"] | +- Literal[@CanonicalImage = "30", @Image = "30"] | +- NumericLiteral[@CanonicalImage = "30", @Image = "30"] +- Statement[@CanonicalImage = null] | +- UnlabelledStatement[@CanonicalImage = null] - | +- Expression[@CanonicalImage = "L_SQL := 'SELECT 1, ' || CHR || 'FIRST KEY' || CHR || ' FROM DUAL ' || ' WHERE ROWNUM <= :P_ROWNUM1 ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'SECOND KEY ' || CHR || ' FROM DUAL' || ' WHERE ROWNUM <= :P_ROWNUM2 '", @Image = "l_sql := 'SELECT 1, ' || CHR || 'First key' || CHR || ' FROM DUAL ' || ' WHERE ROWNUM <= :p_rownum1 ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'Second key ' || CHR || ' FROM DUAL' || ' WHERE ROWNUM <= :p_rownum2 '"] - | +- Assignment[@CanonicalImage = "L_SQL := 'SELECT 1, ' || CHR || 'FIRST KEY' || CHR || ' FROM DUAL ' || ' WHERE ROWNUM <= :P_ROWNUM1 ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'SECOND KEY ' || CHR || ' FROM DUAL' || ' WHERE ROWNUM <= :P_ROWNUM2 '", @Image = "l_sql := 'SELECT 1, ' || CHR || 'First key' || CHR || ' FROM DUAL ' || ' WHERE ROWNUM <= :p_rownum1 ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'Second key ' || CHR || ' FROM DUAL' || ' WHERE ROWNUM <= :p_rownum2 '"] - | +- PrimaryPrefix[@CanonicalImage = "L_SQL", @Image = "l_sql", @SelfModifier = false] + | +- Expression[@CanonicalImage = "L_SQL := \'SELECT 1, \' || CHR || \'FIRST KEY\' || CHR || \' FROM DUAL \' || \' WHERE ROWNUM <= :P_ROWNUM1 \' || \'UNION ALL \' || \'SELECT 2, \' || CHR || \'SECOND KEY \' || CHR || \' FROM DUAL\' || \' WHERE ROWNUM <= :P_ROWNUM2 \'", @Image = "l_sql := \'SELECT 1, \' || CHR || \'First key\' || CHR || \' FROM DUAL \' || \' WHERE ROWNUM <= :p_rownum1 \' || \'UNION ALL \' || \'SELECT 2, \' || CHR || \'Second key \' || CHR || \' FROM DUAL\' || \' WHERE ROWNUM <= :p_rownum2 \'"] + | +- Assignment[@CanonicalImage = "L_SQL := \'SELECT 1, \' || CHR || \'FIRST KEY\' || CHR || \' FROM DUAL \' || \' WHERE ROWNUM <= :P_ROWNUM1 \' || \'UNION ALL \' || \'SELECT 2, \' || CHR || \'SECOND KEY \' || CHR || \' FROM DUAL\' || \' WHERE ROWNUM <= :P_ROWNUM2 \'", @Image = "l_sql := \'SELECT 1, \' || CHR || \'First key\' || CHR || \' FROM DUAL \' || \' WHERE ROWNUM <= :p_rownum1 \' || \'UNION ALL \' || \'SELECT 2, \' || CHR || \'Second key \' || CHR || \' FROM DUAL\' || \' WHERE ROWNUM <= :p_rownum2 \'"] + | +- PrimaryPrefix[@CanonicalImage = "L_SQL", @Image = "l_sql", @SelfModifier = "false"] | | +- SimpleExpression[@CanonicalImage = "L_SQL", @Image = "l_sql"] | | +- Column[@CanonicalImage = "L_SQL", @Image = "l_sql"] | | +- ID[@CanonicalImage = "L_SQL", @Image = "l_sql"] - | +- Expression[@CanonicalImage = "'SELECT 1, ' || CHR || 'FIRST KEY' || CHR || ' FROM DUAL ' || ' WHERE ROWNUM <= :P_ROWNUM1 ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'SECOND KEY ' || CHR || ' FROM DUAL' || ' WHERE ROWNUM <= :P_ROWNUM2 '", @Image = "'SELECT 1, ' || CHR || 'First key' || CHR || ' FROM DUAL ' || ' WHERE ROWNUM <= :p_rownum1 ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'Second key ' || CHR || ' FROM DUAL' || ' WHERE ROWNUM <= :p_rownum2 '"] - | +- AdditiveExpression[@CanonicalImage = "'SELECT 1, ' || CHR || 'FIRST KEY' || CHR || ' FROM DUAL ' || ' WHERE ROWNUM <= :P_ROWNUM1 ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'SECOND KEY ' || CHR || ' FROM DUAL' || ' WHERE ROWNUM <= :P_ROWNUM2 '", @Image = "'SELECT 1, ' || CHR || 'First key' || CHR || ' FROM DUAL ' || ' WHERE ROWNUM <= :p_rownum1 ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'Second key ' || CHR || ' FROM DUAL' || ' WHERE ROWNUM <= :p_rownum2 '"] - | +- PrimaryPrefix[@CanonicalImage = "'SELECT 1, '", @Image = "'SELECT 1, '", @SelfModifier = false] - | | +- Literal[@CanonicalImage = "'SELECT 1, '", @Image = "'SELECT 1, '"] - | | +- StringLiteral[@CanonicalImage = "'SELECT 1, '", @Image = "'SELECT 1, '", @String = "SELECT 1, "] - | +- PrimaryPrefix[@CanonicalImage = "CHR", @Image = "CHR", @SelfModifier = false] + | +- Expression[@CanonicalImage = "\'SELECT 1, \' || CHR || \'FIRST KEY\' || CHR || \' FROM DUAL \' || \' WHERE ROWNUM <= :P_ROWNUM1 \' || \'UNION ALL \' || \'SELECT 2, \' || CHR || \'SECOND KEY \' || CHR || \' FROM DUAL\' || \' WHERE ROWNUM <= :P_ROWNUM2 \'", @Image = "\'SELECT 1, \' || CHR || \'First key\' || CHR || \' FROM DUAL \' || \' WHERE ROWNUM <= :p_rownum1 \' || \'UNION ALL \' || \'SELECT 2, \' || CHR || \'Second key \' || CHR || \' FROM DUAL\' || \' WHERE ROWNUM <= :p_rownum2 \'"] + | +- AdditiveExpression[@CanonicalImage = "\'SELECT 1, \' || CHR || \'FIRST KEY\' || CHR || \' FROM DUAL \' || \' WHERE ROWNUM <= :P_ROWNUM1 \' || \'UNION ALL \' || \'SELECT 2, \' || CHR || \'SECOND KEY \' || CHR || \' FROM DUAL\' || \' WHERE ROWNUM <= :P_ROWNUM2 \'", @Image = "\'SELECT 1, \' || CHR || \'First key\' || CHR || \' FROM DUAL \' || \' WHERE ROWNUM <= :p_rownum1 \' || \'UNION ALL \' || \'SELECT 2, \' || CHR || \'Second key \' || CHR || \' FROM DUAL\' || \' WHERE ROWNUM <= :p_rownum2 \'"] + | +- PrimaryPrefix[@CanonicalImage = "\'SELECT 1, \'", @Image = "\'SELECT 1, \'", @SelfModifier = "false"] + | | +- Literal[@CanonicalImage = "\'SELECT 1, \'", @Image = "\'SELECT 1, \'"] + | | +- StringLiteral[@CanonicalImage = "\'SELECT 1, \'", @Image = "\'SELECT 1, \'", @String = "SELECT 1, "] + | +- PrimaryPrefix[@CanonicalImage = "CHR", @Image = "CHR", @SelfModifier = "false"] | | +- FunctionCall[@CanonicalImage = "CHR", @Image = "CHR"] | | +- FunctionName[@CanonicalImage = "CHR", @Image = "CHR"] | | | +- ID[@CanonicalImage = "CHR", @Image = "CHR"] - | | +- Arguments[@ArgumentCount = 1, @CanonicalImage = null] + | | +- Arguments[@ArgumentCount = "1", @CanonicalImage = null] | | +- ArgumentList[@CanonicalImage = null] | | +- Argument[@CanonicalImage = null] | | +- Expression[@CanonicalImage = "39", @Image = "39"] - | | +- PrimaryPrefix[@CanonicalImage = "39", @Image = "39", @SelfModifier = false] + | | +- PrimaryPrefix[@CanonicalImage = "39", @Image = "39", @SelfModifier = "false"] | | +- Literal[@CanonicalImage = "39", @Image = "39"] | | +- NumericLiteral[@CanonicalImage = "39", @Image = "39"] - | +- PrimaryPrefix[@CanonicalImage = "'FIRST KEY'", @Image = "'First key'", @SelfModifier = false] - | | +- Literal[@CanonicalImage = "'FIRST KEY'", @Image = "'First key'"] - | | +- StringLiteral[@CanonicalImage = "'FIRST KEY'", @Image = "'First key'", @String = "First key"] - | +- PrimaryPrefix[@CanonicalImage = "CHR", @Image = "CHR", @SelfModifier = false] + | +- PrimaryPrefix[@CanonicalImage = "\'FIRST KEY\'", @Image = "\'First key\'", @SelfModifier = "false"] + | | +- Literal[@CanonicalImage = "\'FIRST KEY\'", @Image = "\'First key\'"] + | | +- StringLiteral[@CanonicalImage = "\'FIRST KEY\'", @Image = "\'First key\'", @String = "First key"] + | +- PrimaryPrefix[@CanonicalImage = "CHR", @Image = "CHR", @SelfModifier = "false"] | | +- FunctionCall[@CanonicalImage = "CHR", @Image = "CHR"] | | +- FunctionName[@CanonicalImage = "CHR", @Image = "CHR"] | | | +- ID[@CanonicalImage = "CHR", @Image = "CHR"] - | | +- Arguments[@ArgumentCount = 1, @CanonicalImage = null] + | | +- Arguments[@ArgumentCount = "1", @CanonicalImage = null] | | +- ArgumentList[@CanonicalImage = null] | | +- Argument[@CanonicalImage = null] | | +- Expression[@CanonicalImage = "39", @Image = "39"] - | | +- PrimaryPrefix[@CanonicalImage = "39", @Image = "39", @SelfModifier = false] + | | +- PrimaryPrefix[@CanonicalImage = "39", @Image = "39", @SelfModifier = "false"] | | +- Literal[@CanonicalImage = "39", @Image = "39"] | | +- NumericLiteral[@CanonicalImage = "39", @Image = "39"] - | +- PrimaryPrefix[@CanonicalImage = "' FROM DUAL '", @Image = "' FROM DUAL '", @SelfModifier = false] - | | +- Literal[@CanonicalImage = "' FROM DUAL '", @Image = "' FROM DUAL '"] - | | +- StringLiteral[@CanonicalImage = "' FROM DUAL '", @Image = "' FROM DUAL '", @String = " FROM DUAL "] - | +- PrimaryPrefix[@CanonicalImage = "' WHERE ROWNUM <= :P_ROWNUM1 '", @Image = "' WHERE ROWNUM <= :p_rownum1 '", @SelfModifier = false] - | | +- Literal[@CanonicalImage = "' WHERE ROWNUM <= :P_ROWNUM1 '", @Image = "' WHERE ROWNUM <= :p_rownum1 '"] - | | +- StringLiteral[@CanonicalImage = "' WHERE ROWNUM <= :P_ROWNUM1 '", @Image = "' WHERE ROWNUM <= :p_rownum1 '", @String = " WHERE ROWNUM <= :p_rownum1 "] - | +- PrimaryPrefix[@CanonicalImage = "'UNION ALL '", @Image = "'UNION ALL '", @SelfModifier = false] - | | +- Literal[@CanonicalImage = "'UNION ALL '", @Image = "'UNION ALL '"] - | | +- StringLiteral[@CanonicalImage = "'UNION ALL '", @Image = "'UNION ALL '", @String = "UNION ALL "] - | +- PrimaryPrefix[@CanonicalImage = "'SELECT 2, '", @Image = "'SELECT 2, '", @SelfModifier = false] - | | +- Literal[@CanonicalImage = "'SELECT 2, '", @Image = "'SELECT 2, '"] - | | +- StringLiteral[@CanonicalImage = "'SELECT 2, '", @Image = "'SELECT 2, '", @String = "SELECT 2, "] - | +- PrimaryPrefix[@CanonicalImage = "CHR", @Image = "CHR", @SelfModifier = false] + | +- PrimaryPrefix[@CanonicalImage = "\' FROM DUAL \'", @Image = "\' FROM DUAL \'", @SelfModifier = "false"] + | | +- Literal[@CanonicalImage = "\' FROM DUAL \'", @Image = "\' FROM DUAL \'"] + | | +- StringLiteral[@CanonicalImage = "\' FROM DUAL \'", @Image = "\' FROM DUAL \'", @String = " FROM DUAL "] + | +- PrimaryPrefix[@CanonicalImage = "\' WHERE ROWNUM <= :P_ROWNUM1 \'", @Image = "\' WHERE ROWNUM <= :p_rownum1 \'", @SelfModifier = "false"] + | | +- Literal[@CanonicalImage = "\' WHERE ROWNUM <= :P_ROWNUM1 \'", @Image = "\' WHERE ROWNUM <= :p_rownum1 \'"] + | | +- StringLiteral[@CanonicalImage = "\' WHERE ROWNUM <= :P_ROWNUM1 \'", @Image = "\' WHERE ROWNUM <= :p_rownum1 \'", @String = " WHERE ROWNUM <= :p_rownum1 "] + | +- PrimaryPrefix[@CanonicalImage = "\'UNION ALL \'", @Image = "\'UNION ALL \'", @SelfModifier = "false"] + | | +- Literal[@CanonicalImage = "\'UNION ALL \'", @Image = "\'UNION ALL \'"] + | | +- StringLiteral[@CanonicalImage = "\'UNION ALL \'", @Image = "\'UNION ALL \'", @String = "UNION ALL "] + | +- PrimaryPrefix[@CanonicalImage = "\'SELECT 2, \'", @Image = "\'SELECT 2, \'", @SelfModifier = "false"] + | | +- Literal[@CanonicalImage = "\'SELECT 2, \'", @Image = "\'SELECT 2, \'"] + | | +- StringLiteral[@CanonicalImage = "\'SELECT 2, \'", @Image = "\'SELECT 2, \'", @String = "SELECT 2, "] + | +- PrimaryPrefix[@CanonicalImage = "CHR", @Image = "CHR", @SelfModifier = "false"] | | +- FunctionCall[@CanonicalImage = "CHR", @Image = "CHR"] | | +- FunctionName[@CanonicalImage = "CHR", @Image = "CHR"] | | | +- ID[@CanonicalImage = "CHR", @Image = "CHR"] - | | +- Arguments[@ArgumentCount = 1, @CanonicalImage = null] + | | +- Arguments[@ArgumentCount = "1", @CanonicalImage = null] | | +- ArgumentList[@CanonicalImage = null] | | +- Argument[@CanonicalImage = null] | | +- Expression[@CanonicalImage = "39", @Image = "39"] - | | +- PrimaryPrefix[@CanonicalImage = "39", @Image = "39", @SelfModifier = false] + | | +- PrimaryPrefix[@CanonicalImage = "39", @Image = "39", @SelfModifier = "false"] | | +- Literal[@CanonicalImage = "39", @Image = "39"] | | +- NumericLiteral[@CanonicalImage = "39", @Image = "39"] - | +- PrimaryPrefix[@CanonicalImage = "'SECOND KEY '", @Image = "'Second key '", @SelfModifier = false] - | | +- Literal[@CanonicalImage = "'SECOND KEY '", @Image = "'Second key '"] - | | +- StringLiteral[@CanonicalImage = "'SECOND KEY '", @Image = "'Second key '", @String = "Second key "] - | +- PrimaryPrefix[@CanonicalImage = "CHR", @Image = "CHR", @SelfModifier = false] + | +- PrimaryPrefix[@CanonicalImage = "\'SECOND KEY \'", @Image = "\'Second key \'", @SelfModifier = "false"] + | | +- Literal[@CanonicalImage = "\'SECOND KEY \'", @Image = "\'Second key \'"] + | | +- StringLiteral[@CanonicalImage = "\'SECOND KEY \'", @Image = "\'Second key \'", @String = "Second key "] + | +- PrimaryPrefix[@CanonicalImage = "CHR", @Image = "CHR", @SelfModifier = "false"] | | +- FunctionCall[@CanonicalImage = "CHR", @Image = "CHR"] | | +- FunctionName[@CanonicalImage = "CHR", @Image = "CHR"] | | | +- ID[@CanonicalImage = "CHR", @Image = "CHR"] - | | +- Arguments[@ArgumentCount = 1, @CanonicalImage = null] + | | +- Arguments[@ArgumentCount = "1", @CanonicalImage = null] | | +- ArgumentList[@CanonicalImage = null] | | +- Argument[@CanonicalImage = null] | | +- Expression[@CanonicalImage = "39", @Image = "39"] - | | +- PrimaryPrefix[@CanonicalImage = "39", @Image = "39", @SelfModifier = false] + | | +- PrimaryPrefix[@CanonicalImage = "39", @Image = "39", @SelfModifier = "false"] | | +- Literal[@CanonicalImage = "39", @Image = "39"] | | +- NumericLiteral[@CanonicalImage = "39", @Image = "39"] - | +- PrimaryPrefix[@CanonicalImage = "' FROM DUAL'", @Image = "' FROM DUAL'", @SelfModifier = false] - | | +- Literal[@CanonicalImage = "' FROM DUAL'", @Image = "' FROM DUAL'"] - | | +- StringLiteral[@CanonicalImage = "' FROM DUAL'", @Image = "' FROM DUAL'", @String = " FROM DUAL"] - | +- PrimaryPrefix[@CanonicalImage = "' WHERE ROWNUM <= :P_ROWNUM2 '", @Image = "' WHERE ROWNUM <= :p_rownum2 '", @SelfModifier = false] - | +- Literal[@CanonicalImage = "' WHERE ROWNUM <= :P_ROWNUM2 '", @Image = "' WHERE ROWNUM <= :p_rownum2 '"] - | +- StringLiteral[@CanonicalImage = "' WHERE ROWNUM <= :P_ROWNUM2 '", @Image = "' WHERE ROWNUM <= :p_rownum2 '", @String = " WHERE ROWNUM <= :p_rownum2 "] + | +- PrimaryPrefix[@CanonicalImage = "\' FROM DUAL\'", @Image = "\' FROM DUAL\'", @SelfModifier = "false"] + | | +- Literal[@CanonicalImage = "\' FROM DUAL\'", @Image = "\' FROM DUAL\'"] + | | +- StringLiteral[@CanonicalImage = "\' FROM DUAL\'", @Image = "\' FROM DUAL\'", @String = " FROM DUAL"] + | +- PrimaryPrefix[@CanonicalImage = "\' WHERE ROWNUM <= :P_ROWNUM2 \'", @Image = "\' WHERE ROWNUM <= :p_rownum2 \'", @SelfModifier = "false"] + | +- Literal[@CanonicalImage = "\' WHERE ROWNUM <= :P_ROWNUM2 \'", @Image = "\' WHERE ROWNUM <= :p_rownum2 \'"] + | +- StringLiteral[@CanonicalImage = "\' WHERE ROWNUM <= :P_ROWNUM2 \'", @Image = "\' WHERE ROWNUM <= :p_rownum2 \'", @String = " WHERE ROWNUM <= :p_rownum2 "] +- Statement[@CanonicalImage = null] | +- UnlabelledStatement[@CanonicalImage = null] | +- EmbeddedSqlStatement[@CanonicalImage = null] | +- StringExpression[@CanonicalImage = "L_SQL", @Image = "l_sql"] - | | +- PrimaryPrefix[@CanonicalImage = "L_SQL", @Image = "l_sql", @SelfModifier = false] + | | +- PrimaryPrefix[@CanonicalImage = "L_SQL", @Image = "l_sql", @SelfModifier = "false"] | | +- SimpleExpression[@CanonicalImage = "L_SQL", @Image = "l_sql"] | | +- Column[@CanonicalImage = "L_SQL", @Image = "l_sql"] | | +- ID[@CanonicalImage = "L_SQL", @Image = "l_sql"] @@ -209,12 +179,12 @@ END EXAMPLE_PROCEDURE; | | +- CollectionName[@CanonicalImage = "L_DATA_DESCRIPTION", @Image = "l_data_description"] | | +- ID[@CanonicalImage = "L_DATA_DESCRIPTION", @Image = "l_data_description"] | +- Expression[@CanonicalImage = "P_ROWNUM1", @Image = "p_rownum1"] - | | +- PrimaryPrefix[@CanonicalImage = "P_ROWNUM1", @Image = "p_rownum1", @SelfModifier = false] + | | +- PrimaryPrefix[@CanonicalImage = "P_ROWNUM1", @Image = "p_rownum1", @SelfModifier = "false"] | | +- SimpleExpression[@CanonicalImage = "P_ROWNUM1", @Image = "p_rownum1"] | | +- Column[@CanonicalImage = "P_ROWNUM1", @Image = "p_rownum1"] | | +- ID[@CanonicalImage = "P_ROWNUM1", @Image = "p_rownum1"] | +- Expression[@CanonicalImage = "P_ROWNUM2", @Image = "p_rownum2"] - | +- PrimaryPrefix[@CanonicalImage = "P_ROWNUM2", @Image = "p_rownum2", @SelfModifier = false] + | +- PrimaryPrefix[@CanonicalImage = "P_ROWNUM2", @Image = "p_rownum2", @SelfModifier = "false"] | +- SimpleExpression[@CanonicalImage = "P_ROWNUM2", @Image = "p_rownum2"] | +- Column[@CanonicalImage = "P_ROWNUM2", @Image = "p_rownum2"] | +- ID[@CanonicalImage = "P_ROWNUM2", @Image = "p_rownum2"] diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect3.txt b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect3.txt index f8d384e4c9..9a9b249e0f 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect3.txt +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect3.txt @@ -1,32 +1,7 @@ -+- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0, @Sourcecode = "-- --- BSD-style license; for more info see http://pmd.sourceforge.net/license.html --- - -CREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS - -- - TYPE t_data_key IS TABLE OF NUMBER INDEX BY BINARY_INTEGER; - TYPE t_data_description IS TABLE OF VARCHAR2(100) INDEX BY BINARY_INTEGER; - -- - l_data_key t_data_key; - l_data_description t_data_description; - l_sql VARCHAR2(500); - -- -BEGIN - -- - l_sql := 'SELECT 1, ' || CHR(39) || 'First key' || CHR(39) || - ' FROM DUAL '|| - 'UNION ALL '|| - 'SELECT 2, ' || CHR(39) || 'Second key ' || CHR(39) || - ' FROM DUAL'; - -- - EXECUTE IMMEDIATE l_sql BULK COLLECT - INTO l_data_key, l_data_description; - -- -END EXAMPLE_PROCEDURE; -"] ++- Input[@CanonicalImage = null, @ExcludedLinesCount = "0", @ExcludedRangesCount = "0", @Sourcecode = "--\n-- BSD-style license; for more info see http://pmd.sourceforge.net/license.html\n--\n\nCREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS\n --\n TYPE t_data_key IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;\n TYPE t_data_description IS TABLE OF VARCHAR2(100) INDEX BY BINARY_INTEGER;\n --\n l_data_key t_data_key;\n l_data_description t_data_description;\n l_sql VARCHAR2(500);\n --\nBEGIN\n --\n l_sql := \'SELECT 1, \' || CHR(39) || \'First key\' || CHR(39) || \n \' FROM DUAL \'||\n \'UNION ALL \'||\n \'SELECT 2, \' || CHR(39) || \'Second key \' || CHR(39) || \n \' FROM DUAL\';\n --\n EXECUTE IMMEDIATE l_sql BULK COLLECT\n INTO l_data_key, l_data_description;\n --\nEND EXAMPLE_PROCEDURE;\n"] +- Global[@CanonicalImage = null] +- ProgramUnit[@CanonicalImage = null, @MethodName = "EXAMPLE_PROCEDURE", @Name = "EXAMPLE_PROCEDURE", @ObjectName = null] - +- MethodDeclarator[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE", @ParameterCount = 1] + +- MethodDeclarator[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE", @ParameterCount = "1"] | +- ObjectNameDeclaration[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE"] | +- ID[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE"] +- DeclarativeSection[@CanonicalImage = null] @@ -48,7 +23,7 @@ END EXAMPLE_PROCEDURE; | +- DeclarativeUnit[@CanonicalImage = null] | | +- VariableOrConstantDeclaration[@CanonicalImage = null] | | +- VariableOrConstantDeclarator[@CanonicalImage = "L_DATA_KEY T_DATA_KEY", @Image = "l_data_key t_data_key"] - | | +- VariableOrConstantDeclaratorId[@Array = false, @ArrayDepth = 0, @CanonicalImage = "L_DATA_KEY", @Image = "l_data_key"] + | | +- VariableOrConstantDeclaratorId[@Array = "false", @ArrayDepth = "0", @CanonicalImage = "L_DATA_KEY", @Image = "l_data_key"] | | | +- ID[@CanonicalImage = "L_DATA_KEY", @Image = "l_data_key"] | | +- Datatype[@CanonicalImage = "T_DATA_KEY", @Image = "t_data_key", @TypeImage = "t_data_key"] | | +- QualifiedName[@CanonicalImage = "T_DATA_KEY", @Image = "t_data_key"] @@ -56,7 +31,7 @@ END EXAMPLE_PROCEDURE; | +- DeclarativeUnit[@CanonicalImage = null] | | +- VariableOrConstantDeclaration[@CanonicalImage = null] | | +- VariableOrConstantDeclarator[@CanonicalImage = "L_DATA_DESCRIPTION T_DATA_DESCRIPTION", @Image = "l_data_description t_data_description"] - | | +- VariableOrConstantDeclaratorId[@Array = false, @ArrayDepth = 0, @CanonicalImage = "L_DATA_DESCRIPTION", @Image = "l_data_description"] + | | +- VariableOrConstantDeclaratorId[@Array = "false", @ArrayDepth = "0", @CanonicalImage = "L_DATA_DESCRIPTION", @Image = "l_data_description"] | | | +- ID[@CanonicalImage = "L_DATA_DESCRIPTION", @Image = "l_data_description"] | | +- Datatype[@CanonicalImage = "T_DATA_DESCRIPTION", @Image = "t_data_description", @TypeImage = "t_data_description"] | | +- QualifiedName[@CanonicalImage = "T_DATA_DESCRIPTION", @Image = "t_data_description"] @@ -64,91 +39,91 @@ END EXAMPLE_PROCEDURE; | +- DeclarativeUnit[@CanonicalImage = null] | +- VariableOrConstantDeclaration[@CanonicalImage = null] | +- VariableOrConstantDeclarator[@CanonicalImage = "L_SQL VARCHAR2(500)", @Image = "l_sql VARCHAR2(500)"] - | +- VariableOrConstantDeclaratorId[@Array = false, @ArrayDepth = 0, @CanonicalImage = "L_SQL", @Image = "l_sql"] + | +- VariableOrConstantDeclaratorId[@Array = "false", @ArrayDepth = "0", @CanonicalImage = "L_SQL", @Image = "l_sql"] | | +- ID[@CanonicalImage = "L_SQL", @Image = "l_sql"] | +- Datatype[@CanonicalImage = "VARCHAR2(500)", @Image = "VARCHAR2(500)", @TypeImage = "VARCHAR2(500)"] | +- ScalarDataTypeName[@CanonicalImage = "VARCHAR2(500)", @Image = "VARCHAR2(500)"] | +- NumericLiteral[@CanonicalImage = "500", @Image = "500"] +- Statement[@CanonicalImage = null] | +- UnlabelledStatement[@CanonicalImage = null] - | +- Expression[@CanonicalImage = "L_SQL := 'SELECT 1, ' || CHR || 'FIRST KEY' || CHR || ' FROM DUAL ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'SECOND KEY ' || CHR || ' FROM DUAL'", @Image = "l_sql := 'SELECT 1, ' || CHR || 'First key' || CHR || ' FROM DUAL ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'Second key ' || CHR || ' FROM DUAL'"] - | +- Assignment[@CanonicalImage = "L_SQL := 'SELECT 1, ' || CHR || 'FIRST KEY' || CHR || ' FROM DUAL ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'SECOND KEY ' || CHR || ' FROM DUAL'", @Image = "l_sql := 'SELECT 1, ' || CHR || 'First key' || CHR || ' FROM DUAL ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'Second key ' || CHR || ' FROM DUAL'"] - | +- PrimaryPrefix[@CanonicalImage = "L_SQL", @Image = "l_sql", @SelfModifier = false] + | +- Expression[@CanonicalImage = "L_SQL := \'SELECT 1, \' || CHR || \'FIRST KEY\' || CHR || \' FROM DUAL \' || \'UNION ALL \' || \'SELECT 2, \' || CHR || \'SECOND KEY \' || CHR || \' FROM DUAL\'", @Image = "l_sql := \'SELECT 1, \' || CHR || \'First key\' || CHR || \' FROM DUAL \' || \'UNION ALL \' || \'SELECT 2, \' || CHR || \'Second key \' || CHR || \' FROM DUAL\'"] + | +- Assignment[@CanonicalImage = "L_SQL := \'SELECT 1, \' || CHR || \'FIRST KEY\' || CHR || \' FROM DUAL \' || \'UNION ALL \' || \'SELECT 2, \' || CHR || \'SECOND KEY \' || CHR || \' FROM DUAL\'", @Image = "l_sql := \'SELECT 1, \' || CHR || \'First key\' || CHR || \' FROM DUAL \' || \'UNION ALL \' || \'SELECT 2, \' || CHR || \'Second key \' || CHR || \' FROM DUAL\'"] + | +- PrimaryPrefix[@CanonicalImage = "L_SQL", @Image = "l_sql", @SelfModifier = "false"] | | +- SimpleExpression[@CanonicalImage = "L_SQL", @Image = "l_sql"] | | +- Column[@CanonicalImage = "L_SQL", @Image = "l_sql"] | | +- ID[@CanonicalImage = "L_SQL", @Image = "l_sql"] - | +- Expression[@CanonicalImage = "'SELECT 1, ' || CHR || 'FIRST KEY' || CHR || ' FROM DUAL ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'SECOND KEY ' || CHR || ' FROM DUAL'", @Image = "'SELECT 1, ' || CHR || 'First key' || CHR || ' FROM DUAL ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'Second key ' || CHR || ' FROM DUAL'"] - | +- AdditiveExpression[@CanonicalImage = "'SELECT 1, ' || CHR || 'FIRST KEY' || CHR || ' FROM DUAL ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'SECOND KEY ' || CHR || ' FROM DUAL'", @Image = "'SELECT 1, ' || CHR || 'First key' || CHR || ' FROM DUAL ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'Second key ' || CHR || ' FROM DUAL'"] - | +- PrimaryPrefix[@CanonicalImage = "'SELECT 1, '", @Image = "'SELECT 1, '", @SelfModifier = false] - | | +- Literal[@CanonicalImage = "'SELECT 1, '", @Image = "'SELECT 1, '"] - | | +- StringLiteral[@CanonicalImage = "'SELECT 1, '", @Image = "'SELECT 1, '", @String = "SELECT 1, "] - | +- PrimaryPrefix[@CanonicalImage = "CHR", @Image = "CHR", @SelfModifier = false] + | +- Expression[@CanonicalImage = "\'SELECT 1, \' || CHR || \'FIRST KEY\' || CHR || \' FROM DUAL \' || \'UNION ALL \' || \'SELECT 2, \' || CHR || \'SECOND KEY \' || CHR || \' FROM DUAL\'", @Image = "\'SELECT 1, \' || CHR || \'First key\' || CHR || \' FROM DUAL \' || \'UNION ALL \' || \'SELECT 2, \' || CHR || \'Second key \' || CHR || \' FROM DUAL\'"] + | +- AdditiveExpression[@CanonicalImage = "\'SELECT 1, \' || CHR || \'FIRST KEY\' || CHR || \' FROM DUAL \' || \'UNION ALL \' || \'SELECT 2, \' || CHR || \'SECOND KEY \' || CHR || \' FROM DUAL\'", @Image = "\'SELECT 1, \' || CHR || \'First key\' || CHR || \' FROM DUAL \' || \'UNION ALL \' || \'SELECT 2, \' || CHR || \'Second key \' || CHR || \' FROM DUAL\'"] + | +- PrimaryPrefix[@CanonicalImage = "\'SELECT 1, \'", @Image = "\'SELECT 1, \'", @SelfModifier = "false"] + | | +- Literal[@CanonicalImage = "\'SELECT 1, \'", @Image = "\'SELECT 1, \'"] + | | +- StringLiteral[@CanonicalImage = "\'SELECT 1, \'", @Image = "\'SELECT 1, \'", @String = "SELECT 1, "] + | +- PrimaryPrefix[@CanonicalImage = "CHR", @Image = "CHR", @SelfModifier = "false"] | | +- FunctionCall[@CanonicalImage = "CHR", @Image = "CHR"] | | +- FunctionName[@CanonicalImage = "CHR", @Image = "CHR"] | | | +- ID[@CanonicalImage = "CHR", @Image = "CHR"] - | | +- Arguments[@ArgumentCount = 1, @CanonicalImage = null] + | | +- Arguments[@ArgumentCount = "1", @CanonicalImage = null] | | +- ArgumentList[@CanonicalImage = null] | | +- Argument[@CanonicalImage = null] | | +- Expression[@CanonicalImage = "39", @Image = "39"] - | | +- PrimaryPrefix[@CanonicalImage = "39", @Image = "39", @SelfModifier = false] + | | +- PrimaryPrefix[@CanonicalImage = "39", @Image = "39", @SelfModifier = "false"] | | +- Literal[@CanonicalImage = "39", @Image = "39"] | | +- NumericLiteral[@CanonicalImage = "39", @Image = "39"] - | +- PrimaryPrefix[@CanonicalImage = "'FIRST KEY'", @Image = "'First key'", @SelfModifier = false] - | | +- Literal[@CanonicalImage = "'FIRST KEY'", @Image = "'First key'"] - | | +- StringLiteral[@CanonicalImage = "'FIRST KEY'", @Image = "'First key'", @String = "First key"] - | +- PrimaryPrefix[@CanonicalImage = "CHR", @Image = "CHR", @SelfModifier = false] + | +- PrimaryPrefix[@CanonicalImage = "\'FIRST KEY\'", @Image = "\'First key\'", @SelfModifier = "false"] + | | +- Literal[@CanonicalImage = "\'FIRST KEY\'", @Image = "\'First key\'"] + | | +- StringLiteral[@CanonicalImage = "\'FIRST KEY\'", @Image = "\'First key\'", @String = "First key"] + | +- PrimaryPrefix[@CanonicalImage = "CHR", @Image = "CHR", @SelfModifier = "false"] | | +- FunctionCall[@CanonicalImage = "CHR", @Image = "CHR"] | | +- FunctionName[@CanonicalImage = "CHR", @Image = "CHR"] | | | +- ID[@CanonicalImage = "CHR", @Image = "CHR"] - | | +- Arguments[@ArgumentCount = 1, @CanonicalImage = null] + | | +- Arguments[@ArgumentCount = "1", @CanonicalImage = null] | | +- ArgumentList[@CanonicalImage = null] | | +- Argument[@CanonicalImage = null] | | +- Expression[@CanonicalImage = "39", @Image = "39"] - | | +- PrimaryPrefix[@CanonicalImage = "39", @Image = "39", @SelfModifier = false] + | | +- PrimaryPrefix[@CanonicalImage = "39", @Image = "39", @SelfModifier = "false"] | | +- Literal[@CanonicalImage = "39", @Image = "39"] | | +- NumericLiteral[@CanonicalImage = "39", @Image = "39"] - | +- PrimaryPrefix[@CanonicalImage = "' FROM DUAL '", @Image = "' FROM DUAL '", @SelfModifier = false] - | | +- Literal[@CanonicalImage = "' FROM DUAL '", @Image = "' FROM DUAL '"] - | | +- StringLiteral[@CanonicalImage = "' FROM DUAL '", @Image = "' FROM DUAL '", @String = " FROM DUAL "] - | +- PrimaryPrefix[@CanonicalImage = "'UNION ALL '", @Image = "'UNION ALL '", @SelfModifier = false] - | | +- Literal[@CanonicalImage = "'UNION ALL '", @Image = "'UNION ALL '"] - | | +- StringLiteral[@CanonicalImage = "'UNION ALL '", @Image = "'UNION ALL '", @String = "UNION ALL "] - | +- PrimaryPrefix[@CanonicalImage = "'SELECT 2, '", @Image = "'SELECT 2, '", @SelfModifier = false] - | | +- Literal[@CanonicalImage = "'SELECT 2, '", @Image = "'SELECT 2, '"] - | | +- StringLiteral[@CanonicalImage = "'SELECT 2, '", @Image = "'SELECT 2, '", @String = "SELECT 2, "] - | +- PrimaryPrefix[@CanonicalImage = "CHR", @Image = "CHR", @SelfModifier = false] + | +- PrimaryPrefix[@CanonicalImage = "\' FROM DUAL \'", @Image = "\' FROM DUAL \'", @SelfModifier = "false"] + | | +- Literal[@CanonicalImage = "\' FROM DUAL \'", @Image = "\' FROM DUAL \'"] + | | +- StringLiteral[@CanonicalImage = "\' FROM DUAL \'", @Image = "\' FROM DUAL \'", @String = " FROM DUAL "] + | +- PrimaryPrefix[@CanonicalImage = "\'UNION ALL \'", @Image = "\'UNION ALL \'", @SelfModifier = "false"] + | | +- Literal[@CanonicalImage = "\'UNION ALL \'", @Image = "\'UNION ALL \'"] + | | +- StringLiteral[@CanonicalImage = "\'UNION ALL \'", @Image = "\'UNION ALL \'", @String = "UNION ALL "] + | +- PrimaryPrefix[@CanonicalImage = "\'SELECT 2, \'", @Image = "\'SELECT 2, \'", @SelfModifier = "false"] + | | +- Literal[@CanonicalImage = "\'SELECT 2, \'", @Image = "\'SELECT 2, \'"] + | | +- StringLiteral[@CanonicalImage = "\'SELECT 2, \'", @Image = "\'SELECT 2, \'", @String = "SELECT 2, "] + | +- PrimaryPrefix[@CanonicalImage = "CHR", @Image = "CHR", @SelfModifier = "false"] | | +- FunctionCall[@CanonicalImage = "CHR", @Image = "CHR"] | | +- FunctionName[@CanonicalImage = "CHR", @Image = "CHR"] | | | +- ID[@CanonicalImage = "CHR", @Image = "CHR"] - | | +- Arguments[@ArgumentCount = 1, @CanonicalImage = null] + | | +- Arguments[@ArgumentCount = "1", @CanonicalImage = null] | | +- ArgumentList[@CanonicalImage = null] | | +- Argument[@CanonicalImage = null] | | +- Expression[@CanonicalImage = "39", @Image = "39"] - | | +- PrimaryPrefix[@CanonicalImage = "39", @Image = "39", @SelfModifier = false] + | | +- PrimaryPrefix[@CanonicalImage = "39", @Image = "39", @SelfModifier = "false"] | | +- Literal[@CanonicalImage = "39", @Image = "39"] | | +- NumericLiteral[@CanonicalImage = "39", @Image = "39"] - | +- PrimaryPrefix[@CanonicalImage = "'SECOND KEY '", @Image = "'Second key '", @SelfModifier = false] - | | +- Literal[@CanonicalImage = "'SECOND KEY '", @Image = "'Second key '"] - | | +- StringLiteral[@CanonicalImage = "'SECOND KEY '", @Image = "'Second key '", @String = "Second key "] - | +- PrimaryPrefix[@CanonicalImage = "CHR", @Image = "CHR", @SelfModifier = false] + | +- PrimaryPrefix[@CanonicalImage = "\'SECOND KEY \'", @Image = "\'Second key \'", @SelfModifier = "false"] + | | +- Literal[@CanonicalImage = "\'SECOND KEY \'", @Image = "\'Second key \'"] + | | +- StringLiteral[@CanonicalImage = "\'SECOND KEY \'", @Image = "\'Second key \'", @String = "Second key "] + | +- PrimaryPrefix[@CanonicalImage = "CHR", @Image = "CHR", @SelfModifier = "false"] | | +- FunctionCall[@CanonicalImage = "CHR", @Image = "CHR"] | | +- FunctionName[@CanonicalImage = "CHR", @Image = "CHR"] | | | +- ID[@CanonicalImage = "CHR", @Image = "CHR"] - | | +- Arguments[@ArgumentCount = 1, @CanonicalImage = null] + | | +- Arguments[@ArgumentCount = "1", @CanonicalImage = null] | | +- ArgumentList[@CanonicalImage = null] | | +- Argument[@CanonicalImage = null] | | +- Expression[@CanonicalImage = "39", @Image = "39"] - | | +- PrimaryPrefix[@CanonicalImage = "39", @Image = "39", @SelfModifier = false] + | | +- PrimaryPrefix[@CanonicalImage = "39", @Image = "39", @SelfModifier = "false"] | | +- Literal[@CanonicalImage = "39", @Image = "39"] | | +- NumericLiteral[@CanonicalImage = "39", @Image = "39"] - | +- PrimaryPrefix[@CanonicalImage = "' FROM DUAL'", @Image = "' FROM DUAL'", @SelfModifier = false] - | +- Literal[@CanonicalImage = "' FROM DUAL'", @Image = "' FROM DUAL'"] - | +- StringLiteral[@CanonicalImage = "' FROM DUAL'", @Image = "' FROM DUAL'", @String = " FROM DUAL"] + | +- PrimaryPrefix[@CanonicalImage = "\' FROM DUAL\'", @Image = "\' FROM DUAL\'", @SelfModifier = "false"] + | +- Literal[@CanonicalImage = "\' FROM DUAL\'", @Image = "\' FROM DUAL\'"] + | +- StringLiteral[@CanonicalImage = "\' FROM DUAL\'", @Image = "\' FROM DUAL\'", @String = " FROM DUAL"] +- Statement[@CanonicalImage = null] | +- UnlabelledStatement[@CanonicalImage = null] | +- EmbeddedSqlStatement[@CanonicalImage = null] | +- StringExpression[@CanonicalImage = "L_SQL", @Image = "l_sql"] - | | +- PrimaryPrefix[@CanonicalImage = "L_SQL", @Image = "l_sql", @SelfModifier = false] + | | +- PrimaryPrefix[@CanonicalImage = "L_SQL", @Image = "l_sql", @SelfModifier = "false"] | | +- SimpleExpression[@CanonicalImage = "L_SQL", @Image = "l_sql"] | | +- Column[@CanonicalImage = "L_SQL", @Image = "l_sql"] | | +- ID[@CanonicalImage = "L_SQL", @Image = "l_sql"] From 57dfc7fb40d315106d6882b0b132db82ce55fa4c Mon Sep 17 00:00:00 2001 From: naveen <172697+naveensrinivasan@users.noreply.github.com> Date: Fri, 29 Apr 2022 01:00:46 +0000 Subject: [PATCH 154/180] chore: Set permissions for GitHub actions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Restrict the GitHub token permissions only to the required ones; this way, even if the attackers will succeed in compromising your workflow, they won’t be able to do much. - Included permissions for the action. https://github.com/ossf/scorecard/blob/main/docs/checks.md#token-permissions https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs [Keeping your GitHub Actions and workflows secure Part 1: Preventing pwn requests](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/) Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com> --- .github/workflows/troubleshooting.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/troubleshooting.yml b/.github/workflows/troubleshooting.yml index 31a90eef7f..04ac1cd39c 100644 --- a/.github/workflows/troubleshooting.yml +++ b/.github/workflows/troubleshooting.yml @@ -2,6 +2,9 @@ name: troubleshooting on: workflow_dispatch +permissions: + contents: read + jobs: build: runs-on: ${{ matrix.os }} From c224209d7fe12f0b7e2a1c34b25f6ee562f8addc Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 29 Apr 2022 11:38:52 +0200 Subject: [PATCH 155/180] [test] Backport NodePrinters.kt from pmd7 --- .../pmd/lang/html/ast/PositionTest.java | 18 +- .../lang/html/ast/testdata/SimpleHtmlFile.txt | 21 +- .../lang/html/ast/testdata/SimpleXmlFile.txt | 12 +- .../html/ast/testdata/TemplateFragment.txt | 139 +++++-------- .../ast/jdkversiontests/java15/TextBlocks.txt | 187 +++--------------- .../java16/PatternMatchingInstanceof.txt | 34 ++-- .../java/ast/jdkversiontests/java16/Point.txt | 2 +- .../ast/jdkversiontests/java16/Records.txt | 4 +- .../java17p/DealingWithNull.txt | 28 +-- .../java17p/EnhancedTypeCheckingSwitch.txt | 16 +- .../GuardedAndParenthesizedPatterns.txt | 24 +-- .../java17p/PatternsInSwitchLabels.txt | 8 +- .../ScopeOfPatternVariableDeclarations.txt | 16 +- .../java18p/DealingWithNull.txt | 50 ++--- .../java18p/EnhancedTypeCheckingSwitch.txt | 16 +- .../java18p/ExhaustiveSwitch.txt | 20 +- .../GuardedAndParenthesizedPatterns.txt | 38 ++-- .../java18p/PatternsInSwitchLabels.txt | 8 +- .../java18p/RefiningPatternsInSwitch.txt | 14 +- .../ScopeOfPatternVariableDeclarations.txt | 16 +- .../pmd/lang/ast/test/NodePrinters.kt | 53 +++-- .../ast/ExecuteImmediateBulkCollect1.txt | 33 +--- .../ast/ExecuteImmediateBulkCollect2.txt | 94 +++------ .../ast/ExecuteImmediateBulkCollect3.txt | 77 +++----- .../pmd/lang/plsql/ast/OpenForStatement.txt | 130 ++---------- .../pmd/lang/plsql/ast/ParenthesisGroup0.txt | 27 +-- .../pmd/lang/plsql/ast/ParenthesisGroup1.txt | 27 +-- .../pmd/lang/plsql/ast/ParenthesisGroup2.txt | 29 +-- .../pmd/lang/plsql/ast/ParsingExclusion.txt | 17 +- .../pmd/lang/plsql/ast/SelectIntoArray.txt | 24 +-- .../ast/SqlPlusLexicalVariablesIssue195.txt | 8 +- 31 files changed, 366 insertions(+), 824 deletions(-) diff --git a/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/ast/PositionTest.java b/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/ast/PositionTest.java index 37b7d21322..c4169de683 100644 --- a/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/ast/PositionTest.java +++ b/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/ast/PositionTest.java @@ -5,20 +5,15 @@ package net.sourceforge.pmd.lang.html.ast; -import java.util.Set; - import org.junit.Test; -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.ast.test.BaseNodeAttributePrinter; import net.sourceforge.pmd.lang.ast.test.BaseParsingHelper; import net.sourceforge.pmd.lang.ast.test.BaseTreeDumpTest; -import net.sourceforge.pmd.lang.ast.xpath.Attribute; -import net.sourceforge.pmd.util.CollectionUtil; +import net.sourceforge.pmd.lang.ast.test.CoordinatesPrinter; public class PositionTest extends BaseTreeDumpTest { public PositionTest() { - super(new PositionRenderer(), ".html"); + super(CoordinatesPrinter.INSTANCE, ".html"); } @Override @@ -30,13 +25,4 @@ public class PositionTest extends BaseTreeDumpTest { public void testPositions() { doTest("SimpleHtmlFile2"); } - - private static class PositionRenderer extends BaseNodeAttributePrinter { - private final Set pos = CollectionUtil.asSet(new String[] {"BeginLine", "BeginColumn", "EndLine", "EndColumn"}); - - @Override - protected boolean ignoreAttribute(Node node, Attribute attribute) { - return !pos.contains(attribute.getName()); - } - } } diff --git a/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/ast/testdata/SimpleHtmlFile.txt b/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/ast/testdata/SimpleHtmlFile.txt index 058a83898d..6d8af325b6 100644 --- a/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/ast/testdata/SimpleHtmlFile.txt +++ b/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/ast/testdata/SimpleHtmlFile.txt @@ -1,22 +1,15 @@ +- #document[@NodeName = "#document"] +- #doctype[@Name = "html", @NodeName = "#doctype", @PublicId = "", @SystemId = ""] - +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " -"] + +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n"] +- html[@NodeName = "html"] - | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | +- head[@NodeName = "head"] | | +- #text[@Image = "hello", @NodeName = "#text", @NormalizedText = "hello", @Text = "hello"] - | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | +- body[@NodeName = "body"] - | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | +- h1[@NodeName = "h1"] | | | +- #text[@Image = "world", @NodeName = "#text", @NormalizedText = "world", @Text = "world"] - | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] - | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " -"] - +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " -"] + | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] + | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n"] + +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n"] diff --git a/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/ast/testdata/SimpleXmlFile.txt b/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/ast/testdata/SimpleXmlFile.txt index a5c715bfb0..9c25c1a1fc 100644 --- a/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/ast/testdata/SimpleXmlFile.txt +++ b/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/ast/testdata/SimpleXmlFile.txt @@ -1,13 +1,9 @@ +- #document[@NodeName = "#document"] +- #declaration[@Name = "xml", @NodeName = "#declaration"] - +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " -"] + +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n"] +- root[@NodeName = "root"] - | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | +- child[@NodeName = "child", @attr1 = "value1"] | | +- #text[@Image = "text & entities", @NodeName = "#text", @NormalizedText = "text & entities", @Text = "text & entities"] - | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " -"] - +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " -"] + | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n"] + +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n"] diff --git a/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/ast/testdata/TemplateFragment.txt b/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/ast/testdata/TemplateFragment.txt index c9e048e3be..6b4d6a4f40 100644 --- a/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/ast/testdata/TemplateFragment.txt +++ b/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/ast/testdata/TemplateFragment.txt @@ -1,130 +1,83 @@ +- #document[@NodeName = "#document"] +- #comment[@Data = " from https://raw.githubusercontent.com/trailheadapps/lwc-recipes-oss/main/src/modules/ui/app/app.html ", @NodeName = "#comment"] - +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " -"] + +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n"] +- template[@NodeName = "template"] - | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | +- section[@NodeName = "section", @class = "content container page-background"] - | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | +- ui-navbar[@NodeName = "ui-navbar", @nav-items = "{navigationItems}", @oncategorychange = "{handleCategoryChange}", @selected-item = "{currentNavigationItem}"] - | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] - | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - - "] + | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] + | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n\n "] | | +- article[@NodeName = "article", @class = "container"] - | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | +- div[@NodeName = "div"] - | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | +- template[@NodeName = "template", @if:true = "{navigationItems.hello.visible}"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-hello[@NodeName = "recipe-hello"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-hello-binding[@NodeName = "recipe-hello-binding"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-hello-expressions[@NodeName = "recipe-hello-expressions"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-hello-expressions-track[@NodeName = "recipe-hello-expressions-track"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-hello-conditional-rendering[@NodeName = "recipe-hello-conditional-rendering"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-hello-for-each[@NodeName = "recipe-hello-for-each"] | | | | | +- recipe-hello-iterator[@NodeName = "recipe-hello-iterator"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] - | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] + | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | +- template[@NodeName = "template", @if:true = "{navigationItems.composition.visible}"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-composition-basics[@NodeName = "recipe-composition-basics"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-composition-iteration[@NodeName = "recipe-composition-iteration"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-composition-contact-search[@NodeName = "recipe-composition-contact-search"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-composition-dynamic[@NodeName = "recipe-composition-dynamic"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] - | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] + | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | +- template[@NodeName = "template", @if:true = "{navigationItems.child.visible}"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-event-simple[@NodeName = "recipe-event-simple"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-event-with-data[@NodeName = "recipe-event-with-data"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-event-bubbling[@NodeName = "recipe-event-bubbling"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] - | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] + | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | +- template[@NodeName = "template", @if:true = "{navigationItems.parent.visible}"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-api-property[@NodeName = "recipe-api-property"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-api-function[@NodeName = "recipe-api-function"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-api-setter-getter[@NodeName = "recipe-api-setter-getter"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] - | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] + | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | +- template[@NodeName = "template", @if:true = "{navigationItems.misc.visible}"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-misc-shared-java-script[@NodeName = "recipe-misc-shared-java-script"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-misc-rest-api-call[@NodeName = "recipe-misc-rest-api-call"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-misc-dom-query[@NodeName = "recipe-misc-dom-query"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-misc-multiple-templates[@NodeName = "recipe-misc-multiple-templates"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] - | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] + | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | +- template[@NodeName = "template", @if:true = "{navigationItems.party.visible}"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-libs-d3[@NodeName = "recipe-libs-d3"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | | +- recipe-libs-chartjs[@NodeName = "recipe-libs-chartjs"] - | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] - | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] + | | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] + | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] | | | | +- ui-navfooter[@NodeName = "ui-navfooter", @label-next = "{nextNavigationItem}", @label-previous = "{previousNavigationItem}", @onnextclicked = "{handleNavigateNext}", @onpreviousclicked = "{handleNavigatePrevious}"] - | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] - | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] - | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " - "] - | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " -"] - +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = " -"] + | | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] + | | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] + | | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n "] + | +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n"] + +- #text[@Image = " ", @NodeName = "#text", @NormalizedText = " ", @Text = "\n"] diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java15/TextBlocks.txt b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java15/TextBlocks.txt index bf7dda49e0..0077112339 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java15/TextBlocks.txt +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java15/TextBlocks.txt @@ -30,24 +30,7 @@ | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = """" - - -

    Hello, world

    - - - """", @FloatLiteral = false, @Image = """" - - -

    Hello, world

    - - - """", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = true, @TextBlockContent = " - -

    Hello, world

    - - -", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"\"\"\n \n \n

    Hello, world

    \n \n \n \"\"\"", @FloatLiteral = false, @Image = "\"\"\"\n \n \n

    Hello, world

    \n \n \n \"\"\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = true, @TextBlockContent = "\n \n

    Hello, world

    \n \n\n", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- BlockStatement[@Allocation = false] | +- Statement[] | +- StatementExpression[] @@ -72,18 +55,7 @@ | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = """" - SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB` - WHERE `CITY` = 'INDIANAPOLIS' - ORDER BY `EMP_ID`, `LAST_NAME`; - """", @FloatLiteral = false, @Image = """" - SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB` - WHERE `CITY` = 'INDIANAPOLIS' - ORDER BY `EMP_ID`, `LAST_NAME`; - """", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = true, @TextBlockContent = "SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB` -WHERE `CITY` = 'INDIANAPOLIS' -ORDER BY `EMP_ID`, `LAST_NAME`; -", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"\"\"\n SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`\n WHERE `CITY` = \'INDIANAPOLIS\'\n ORDER BY `EMP_ID`, `LAST_NAME`;\n \"\"\"", @FloatLiteral = false, @Image = "\"\"\"\n SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`\n WHERE `CITY` = \'INDIANAPOLIS\'\n ORDER BY `EMP_ID`, `LAST_NAME`;\n \"\"\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = true, @TextBlockContent = "SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`\nWHERE `CITY` = \'INDIANAPOLIS\'\nORDER BY `EMP_ID`, `LAST_NAME`;\n", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- BlockStatement[@Allocation = false] | +- Statement[] | +- StatementExpression[] @@ -118,7 +90,7 @@ ORDER BY `EMP_ID`, `LAST_NAME`; | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""js"", @FloatLiteral = false, @Image = ""js"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""js"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"js\"", @FloatLiteral = false, @Image = "\"js\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"js\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- BlockStatement[@Allocation = false] | +- LocalVariableDeclaration[@Abstract = false, @Array = false, @ArrayDepth = 0, @Default = false, @Final = false, @Modifiers = 0, @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeInferred = false, @VariableName = "obj", @Volatile = false] | +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "Object"] @@ -137,24 +109,7 @@ ORDER BY `EMP_ID`, `LAST_NAME`; | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = """" - function hello() { - print('"Hello, world"'); - } - - hello(); - """", @FloatLiteral = false, @Image = """" - function hello() { - print('"Hello, world"'); - } - - hello(); - """", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = true, @TextBlockContent = "function hello() { - print('"Hello, world"'); -} - -hello(); -", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"\"\"\n function hello() {\n print(\'\"Hello, world\"\');\n }\n \n hello();\n \"\"\"", @FloatLiteral = false, @Image = "\"\"\"\n function hello() {\n print(\'\"Hello, world\"\');\n }\n \n hello();\n \"\"\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = true, @TextBlockContent = "function hello() {\n print(\'\"Hello, world\"\');\n}\n\nhello();\n", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- BlockStatement[@Allocation = false] | +- LocalVariableDeclaration[@Abstract = false, @Array = false, @ArrayDepth = 0, @Default = false, @Final = false, @Modifiers = 0, @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeInferred = false, @VariableName = "htmlWithEscapes", @Volatile = false] | +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "String"] @@ -166,24 +121,7 @@ hello(); | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = """" - - -

    Hello, world

    - - - """", @FloatLiteral = false, @Image = """" - - -

    Hello, world

    - - - """", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = true, @TextBlockContent = " - -

    Hello, world

    - - -", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"\"\"\n \\r\n \\r\n

    Hello, world

    \\r\n \\r\n \\r\n \"\"\"", @FloatLiteral = false, @Image = "\"\"\"\n \\r\n \\r\n

    Hello, world

    \\r\n \\r\n \\r\n \"\"\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = true, @TextBlockContent = "\r\n \r\n

    Hello, world

    \r\n \r\n\r\n", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- BlockStatement[@Allocation = false] | +- Statement[] | +- StatementExpression[] @@ -208,9 +146,7 @@ hello(); | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = """" - winter"""", @FloatLiteral = false, @Image = """" - winter"""", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = true, @TextBlockContent = "winter", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"\"\"\n winter\"\"\"", @FloatLiteral = false, @Image = "\"\"\"\n winter\"\"\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = true, @TextBlockContent = "winter", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- BlockStatement[@Allocation = false] | +- LocalVariableDeclaration[@Abstract = false, @Array = false, @ArrayDepth = 0, @Default = false, @Final = false, @Modifiers = 0, @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeInferred = false, @VariableName = "period", @Volatile = false] | +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "String"] @@ -222,12 +158,7 @@ hello(); | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = """" - winter - """", @FloatLiteral = false, @Image = """" - winter - """", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = true, @TextBlockContent = "winter -", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"\"\"\n winter\n \"\"\"", @FloatLiteral = false, @Image = "\"\"\"\n winter\n \"\"\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = true, @TextBlockContent = "winter\n", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- BlockStatement[@Allocation = false] | +- LocalVariableDeclaration[@Abstract = false, @Array = false, @ArrayDepth = 0, @Default = false, @Final = false, @Modifiers = 0, @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeInferred = false, @VariableName = "greeting", @Volatile = false] | +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "String"] @@ -239,12 +170,7 @@ hello(); | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = """" - Hi, "Bob" - """", @FloatLiteral = false, @Image = """" - Hi, "Bob" - """", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = true, @TextBlockContent = "Hi, "Bob" -", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"\"\"\n Hi, \"Bob\"\n \"\"\"", @FloatLiteral = false, @Image = "\"\"\"\n Hi, \"Bob\"\n \"\"\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = true, @TextBlockContent = "Hi, \"Bob\"\n", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- BlockStatement[@Allocation = false] | +- LocalVariableDeclaration[@Abstract = false, @Array = false, @ArrayDepth = 0, @Default = false, @Final = false, @Modifiers = 0, @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeInferred = false, @VariableName = "salutation", @Volatile = false] | +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "String"] @@ -256,15 +182,7 @@ hello(); | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = """" - Hi, - "Bob" - """", @FloatLiteral = false, @Image = """" - Hi, - "Bob" - """", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = true, @TextBlockContent = "Hi, - "Bob" -", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"\"\"\n Hi,\n \"Bob\"\n \"\"\"", @FloatLiteral = false, @Image = "\"\"\"\n Hi,\n \"Bob\"\n \"\"\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = true, @TextBlockContent = "Hi,\n \"Bob\"\n", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- BlockStatement[@Allocation = false] | +- LocalVariableDeclaration[@Abstract = false, @Array = false, @ArrayDepth = 0, @Default = false, @Final = false, @Modifiers = 0, @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeInferred = false, @VariableName = "empty", @Volatile = false] | +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "String"] @@ -276,9 +194,7 @@ hello(); | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = """" - """", @FloatLiteral = false, @Image = """" - """", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = true, @TextBlockContent = "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"\"\"\n \"\"\"", @FloatLiteral = false, @Image = "\"\"\"\n \"\"\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = true, @TextBlockContent = "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- BlockStatement[@Allocation = false] | +- LocalVariableDeclaration[@Abstract = false, @Array = false, @ArrayDepth = 0, @Default = false, @Final = false, @Modifiers = 0, @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeInferred = false, @VariableName = "quote", @Volatile = false] | +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "String"] @@ -290,12 +206,7 @@ hello(); | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = """" - " - """", @FloatLiteral = false, @Image = """" - " - """", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = true, @TextBlockContent = "" -", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"\"\"\n \"\n \"\"\"", @FloatLiteral = false, @Image = "\"\"\"\n \"\n \"\"\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = true, @TextBlockContent = "\"\n", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- BlockStatement[@Allocation = false] | +- LocalVariableDeclaration[@Abstract = false, @Array = false, @ArrayDepth = 0, @Default = false, @Final = false, @Modifiers = 0, @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeInferred = false, @VariableName = "backslash", @Volatile = false] | +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "String"] @@ -307,12 +218,7 @@ hello(); | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = """" - \ - """", @FloatLiteral = false, @Image = """" - \ - """", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = true, @TextBlockContent = " -", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"\"\"\n \\\\\n \"\"\"", @FloatLiteral = false, @Image = "\"\"\"\n \\\\\n \"\"\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = true, @TextBlockContent = "\\\n", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- BlockStatement[@Allocation = false] | +- LocalVariableDeclaration[@Abstract = false, @Array = false, @ArrayDepth = 0, @Default = false, @Final = false, @Modifiers = 0, @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeInferred = false, @VariableName = "normalStringLiteral", @Volatile = false] | +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "String"] @@ -324,7 +230,7 @@ hello(); | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""test"", @FloatLiteral = false, @Image = ""test"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""test"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"test\"", @FloatLiteral = false, @Image = "\"test\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"test\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- BlockStatement[@Allocation = false] | +- LocalVariableDeclaration[@Abstract = false, @Array = false, @ArrayDepth = 0, @Default = false, @Final = false, @Modifiers = 0, @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeInferred = false, @VariableName = "code", @Volatile = false] | +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "String"] @@ -336,18 +242,7 @@ hello(); | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = """" - String text = """ - A text block inside a text block - """; - """", @FloatLiteral = false, @Image = """" - String text = """ - A text block inside a text block - """; - """", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = true, @TextBlockContent = "String text = """ - A text block inside a text block -"""; -", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"\"\"\n String text = \\\"\"\"\n A text block inside a text block\n \\\"\"\";\n \"\"\"", @FloatLiteral = false, @Image = "\"\"\"\n String text = \\\"\"\"\n A text block inside a text block\n \\\"\"\";\n \"\"\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = true, @TextBlockContent = "String text = \"\"\"\n A text block inside a text block\n\"\"\";\n", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- BlockStatement[@Allocation = false] | +- LocalVariableDeclaration[@Abstract = false, @Array = false, @ArrayDepth = 0, @Default = false, @Final = false, @Modifiers = 0, @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeInferred = false, @VariableName = "text", @Volatile = false] | +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "String"] @@ -359,15 +254,7 @@ hello(); | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = """" - Lorem ipsum dolor sit amet, consectetur adipiscing - elit, sed do eiusmod tempor incididunt ut labore - et dolore magna aliqua. - """", @FloatLiteral = false, @Image = """" - Lorem ipsum dolor sit amet, consectetur adipiscing - elit, sed do eiusmod tempor incididunt ut labore - et dolore magna aliqua. - """", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = true, @TextBlockContent = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"\"\"\n Lorem ipsum dolor sit amet, consectetur adipiscing \\\n elit, sed do eiusmod tempor incididunt ut labore \\\n et dolore magna aliqua.\\\n \"\"\"", @FloatLiteral = false, @Image = "\"\"\"\n Lorem ipsum dolor sit amet, consectetur adipiscing \\\n elit, sed do eiusmod tempor incididunt ut labore \\\n et dolore magna aliqua.\\\n \"\"\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = true, @TextBlockContent = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- BlockStatement[@Allocation = false] | +- Statement[] | +- StatementExpression[] @@ -392,18 +279,7 @@ hello(); | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = """" - red s - greens - blue s - """", @FloatLiteral = false, @Image = """" - red s - greens - blue s - """", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = true, @TextBlockContent = "red -green -blue -", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"\"\"\n red \\s\n green\\s\n blue \\s\n \"\"\"", @FloatLiteral = false, @Image = "\"\"\"\n red \\s\n green\\s\n blue \\s\n \"\"\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = true, @TextBlockContent = "red \ngreen \nblue \n", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- BlockStatement[@Allocation = false] | +- Statement[] | +- StatementExpression[] @@ -428,15 +304,7 @@ blue | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = """" - -test -"""", @FloatLiteral = false, @Image = """" - -test -"""", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = true, @TextBlockContent = " -test -", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"\"\"\n\ntest\n\"\"\"", @FloatLiteral = false, @Image = "\"\"\"\n\ntest\n\"\"\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = true, @TextBlockContent = "\ntest\n", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- BlockStatement[@Allocation = false] | +- Statement[] | +- StatementExpression[] @@ -456,14 +324,11 @@ test | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "" -"", @FloatLiteral = false, @Image = "" -"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = true, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "" -"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"\\n\"", @FloatLiteral = false, @Image = "\"\\n\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = true, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"\\n\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = """", @FloatLiteral = false, @Image = """", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = """", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"\"", @FloatLiteral = false, @Image = "\"\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- BlockStatement[@Allocation = false] | +- LocalVariableDeclaration[@Abstract = false, @Array = false, @ArrayDepth = 0, @Default = false, @Final = false, @Modifiers = 0, @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = false, @Strictfp = false, @Synchronized = false, @Transient = false, @TypeInferred = false, @VariableName = "bs", @Volatile = false] | +- Type[@Array = false, @ArrayDepth = 0, @ArrayType = false, @TypeImage = "String"] @@ -475,12 +340,7 @@ test | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = """" - \test - """", @FloatLiteral = false, @Image = """" - \test - """", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = true, @TextBlockContent = " est -", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"\"\"\n \\\\test\n \"\"\"", @FloatLiteral = false, @Image = "\"\"\"\n \\\\test\n \"\"\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = true, @TextBlockContent = "\\test\n", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- BlockStatement[@Allocation = false] +- Statement[] +- StatementExpression[] @@ -500,11 +360,8 @@ test +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "" -"", @FloatLiteral = false, @Image = "" -"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = true, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "" -"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"\\n\"", @FloatLiteral = false, @Image = "\"\\n\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = true, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"\\n\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- Expression[@StandAlonePrimitive = false] +- PrimaryExpression[] +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = """", @FloatLiteral = false, @Image = """", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = """", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"\"", @FloatLiteral = false, @Image = "\"\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/PatternMatchingInstanceof.txt b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/PatternMatchingInstanceof.txt index 07cc3abbd3..00f533dd0e 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/PatternMatchingInstanceof.txt +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/PatternMatchingInstanceof.txt @@ -13,7 +13,7 @@ | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""other string"", @FloatLiteral = false, @Image = ""other string"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""other string"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"other string\"", @FloatLiteral = false, @Image = "\"other string\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"other string\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.METHOD] | +- MethodDeclaration[@Abstract = false, @Arity = 0, @Default = false, @Final = false, @InterfaceMember = false, @Kind = MethodLikeKind.METHOD, @MethodName = "test", @Modifiers = 1, @Name = "test", @Native = false, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @Static = false, @Strictfp = false, @Synchronized = false, @SyntacticallyAbstract = false, @SyntacticallyPublic = true, @Transient = false, @Void = true, @Volatile = false] | +- ResultType[@Void = true, @returnsArray = false] @@ -31,7 +31,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""abc"", @FloatLiteral = false, @Image = ""abc"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""abc"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"abc\"", @FloatLiteral = false, @Image = "\"abc\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"abc\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- BlockStatement[@Allocation = false] | | +- Statement[] | | +- IfStatement[@Else = true] @@ -60,7 +60,7 @@ | | | | +- AdditiveExpression[@Image = "+", @Operator = "+"] | | | | +- PrimaryExpression[] | | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""a) obj == s: "", @FloatLiteral = false, @Image = ""a) obj == s: "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""a) obj == s: "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"a) obj == s: \"", @FloatLiteral = false, @Image = "\"a) obj == s: \"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"a) obj == s: \"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | | | +- PrimaryExpression[] | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] | | | | +- Expression[@StandAlonePrimitive = false] @@ -81,7 +81,7 @@ | | | | +- Expression[@StandAlonePrimitive = false] | | | | +- PrimaryExpression[] | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""other value"", @FloatLiteral = false, @Image = ""other value"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""other value"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"other value\"", @FloatLiteral = false, @Image = "\"other value\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"other value\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | | +- BlockStatement[@Allocation = false] | | | +- Statement[] | | | +- StatementExpression[] @@ -95,13 +95,13 @@ | | | +- AdditiveExpression[@Image = "+", @Operator = "+"] | | | +- PrimaryExpression[] | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""changed s to "", @FloatLiteral = false, @Image = ""changed s to "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""changed s to "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"changed s to \"", @FloatLiteral = false, @Image = "\"changed s to \"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"changed s to \"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | | +- PrimaryExpression[] | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] | | | | +- Name[@Image = "s"] | | | +- PrimaryExpression[] | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "": obj == s: "", @FloatLiteral = false, @Image = "": obj == s: "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "": obj == s: "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\": obj == s: \"", @FloatLiteral = false, @Image = "\": obj == s: \"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\": obj == s: \"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] | | | +- Expression[@StandAlonePrimitive = false] @@ -127,7 +127,7 @@ | | +- AdditiveExpression[@Image = "+", @Operator = "+"] | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""b) obj == s: "", @FloatLiteral = false, @Image = ""b) obj == s: "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""b) obj == s: "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"b) obj == s: \"", @FloatLiteral = false, @Image = "\"b) obj == s: \"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"b) obj == s: \"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] | | +- Expression[@StandAlonePrimitive = false] @@ -170,7 +170,7 @@ | | | +- AdditiveExpression[@Image = "+", @Operator = "+"] | | | +- PrimaryExpression[] | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""c) obj == s: "", @FloatLiteral = false, @Image = ""c) obj == s: "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""c) obj == s: "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"c) obj == s: \"", @FloatLiteral = false, @Image = "\"c) obj == s: \"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"c) obj == s: \"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] | | | +- Expression[@StandAlonePrimitive = false] @@ -196,7 +196,7 @@ | | +- AdditiveExpression[@Image = "+", @Operator = "+"] | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""d) obj == s: "", @FloatLiteral = false, @Image = ""d) obj == s: "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""d) obj == s: "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"d) obj == s: \"", @FloatLiteral = false, @Image = "\"d) obj == s: \"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"d) obj == s: \"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] | | +- Expression[@StandAlonePrimitive = false] @@ -245,7 +245,7 @@ | | +- AdditiveExpression[@Image = "+", @Operator = "+"] | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""e) obj == s: "", @FloatLiteral = false, @Image = ""e) obj == s: "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""e) obj == s: "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"e) obj == s: \"", @FloatLiteral = false, @Image = "\"e) obj == s: \"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"e) obj == s: \"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] | | +- Expression[@StandAlonePrimitive = false] @@ -294,7 +294,7 @@ | | +- AdditiveExpression[@Image = "+", @Operator = "+"] | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""f) obj == s: "", @FloatLiteral = false, @Image = ""f) obj == s: "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""f) obj == s: "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"f) obj == s: \"", @FloatLiteral = false, @Image = "\"f) obj == s: \"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"f) obj == s: \"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] | | +- Expression[@StandAlonePrimitive = false] @@ -333,7 +333,7 @@ | | | +- AdditiveExpression[@Image = "+", @Operator = "+"] | | | +- PrimaryExpression[] | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""g) obj == s: "", @FloatLiteral = false, @Image = ""g) obj == s: "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""g) obj == s: "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"g) obj == s: \"", @FloatLiteral = false, @Image = "\"g) obj == s: \"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"g) obj == s: \"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] | | | +- Expression[@StandAlonePrimitive = false] @@ -359,7 +359,7 @@ | | +- AdditiveExpression[@Image = "+", @Operator = "+"] | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""h) obj == s: "", @FloatLiteral = false, @Image = ""h) obj == s: "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""h) obj == s: "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"h) obj == s: \"", @FloatLiteral = false, @Image = "\"h) obj == s: \"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"h) obj == s: \"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] | | +- Expression[@StandAlonePrimitive = false] @@ -401,7 +401,7 @@ | | | +- AdditiveExpression[@Image = "+", @Operator = "+"] | | | +- PrimaryExpression[] | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""i) obj == s: "", @FloatLiteral = false, @Image = ""i) obj == s: "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""i) obj == s: "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"i) obj == s: \"", @FloatLiteral = false, @Image = "\"i) obj == s: \"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"i) obj == s: \"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] | | | +- Expression[@StandAlonePrimitive = false] @@ -427,7 +427,7 @@ | | +- AdditiveExpression[@Image = "+", @Operator = "+"] | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""j) obj == s: "", @FloatLiteral = false, @Image = ""j) obj == s: "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""j) obj == s: "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"j) obj == s: \"", @FloatLiteral = false, @Image = "\"j) obj == s: \"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"j) obj == s: \"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] | | +- Expression[@StandAlonePrimitive = false] @@ -469,7 +469,7 @@ | | +- AdditiveExpression[@Image = "+", @Operator = "+"] | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""k) obj == s: "", @FloatLiteral = false, @Image = ""k) obj == s: "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""k) obj == s: "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"k) obj == s: \"", @FloatLiteral = false, @Image = "\"k) obj == s: \"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"k) obj == s: \"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] | | +- Expression[@StandAlonePrimitive = false] @@ -495,7 +495,7 @@ | +- AdditiveExpression[@Image = "+", @Operator = "+"] | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""l) obj == s: "", @FloatLiteral = false, @Image = ""l) obj == s: "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""l) obj == s: "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"l) obj == s: \"", @FloatLiteral = false, @Image = "\"l) obj == s: \"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"l) obj == s: \"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] | +- Expression[@StandAlonePrimitive = false] diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/Point.txt b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/Point.txt index 341c9f28da..90d0291656 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/Point.txt +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/Point.txt @@ -58,7 +58,7 @@ +- AdditiveExpression[@Image = "+", @Operator = "+"] +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""p = "", @FloatLiteral = false, @Image = ""p = "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""p = "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"p = \"", @FloatLiteral = false, @Image = "\"p = \"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"p = \"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- PrimaryExpression[] +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] +- Name[@Image = "p"] diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/Records.txt b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/Records.txt index dbdbaa18b7..d0248e939c 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/Records.txt +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java16/Records.txt @@ -89,7 +89,7 @@ | | | +- Expression[@StandAlonePrimitive = false] | | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""too big"", @FloatLiteral = false, @Image = ""too big"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""too big"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"too big\"", @FloatLiteral = false, @Image = "\"too big\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"too big\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | +- BlockStatement[@Allocation = false] | | | +- Statement[] | | | +- StatementExpression[] @@ -170,7 +170,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""(%d,%d)"", @FloatLiteral = false, @Image = ""(%d,%d)"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""(%d,%d)"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"(%d,%d)\"", @FloatLiteral = false, @Image = "\"(%d,%d)\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"(%d,%d)\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | +- Expression[@StandAlonePrimitive = false] | | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java17p/DealingWithNull.txt b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java17p/DealingWithNull.txt index f7395cff4e..2e81b3be14 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java17p/DealingWithNull.txt +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java17p/DealingWithNull.txt @@ -37,7 +37,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""null!"", @FloatLiteral = false, @Image = ""null!"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""null!"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"null!\"", @FloatLiteral = false, @Image = "\"null!\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"null!\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- SwitchLabeledExpression[] | | +- SwitchLabel[@Default = false] | | | +- TypePattern[@ParenthesisDepth = 0] @@ -55,7 +55,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""String"", @FloatLiteral = false, @Image = ""String"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""String"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"String\"", @FloatLiteral = false, @Image = "\"String\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"String\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- SwitchLabeledExpression[] | +- SwitchLabel[@Default = true] | +- Expression[@StandAlonePrimitive = false] @@ -68,7 +68,7 @@ | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""Something else"", @FloatLiteral = false, @Image = ""Something else"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""Something else"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Something else\"", @FloatLiteral = false, @Image = "\"Something else\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Something else\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.METHOD] | +- MethodDeclaration[@Abstract = false, @Arity = 1, @Default = false, @Final = false, @InterfaceMember = false, @Kind = MethodLikeKind.METHOD, @MethodName = "test2", @Modifiers = 16, @Name = "test2", @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = true, @Strictfp = false, @Synchronized = false, @SyntacticallyAbstract = false, @SyntacticallyPublic = false, @Transient = false, @Void = true, @Volatile = false] | +- ResultType[@Void = true, @returnsArray = false] @@ -119,7 +119,7 @@ | | +- AdditiveExpression[@Image = "+", @Operator = "+"] | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""String: "", @FloatLiteral = false, @Image = ""String: "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""String: "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"String: \"", @FloatLiteral = false, @Image = "\"String: \"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"String: \"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] | | +- Name[@Image = "s"] @@ -140,7 +140,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""Integer"", @FloatLiteral = false, @Image = ""Integer"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""Integer"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Integer\"", @FloatLiteral = false, @Image = "\"Integer\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Integer\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- SwitchLabeledExpression[] | +- SwitchLabel[@Default = true] | +- Expression[@StandAlonePrimitive = false] @@ -153,7 +153,7 @@ | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""default"", @FloatLiteral = false, @Image = ""default"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""default"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"default\"", @FloatLiteral = false, @Image = "\"default\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"default\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.METHOD] | +- MethodDeclaration[@Abstract = false, @Arity = 1, @Default = false, @Final = false, @InterfaceMember = false, @Kind = MethodLikeKind.METHOD, @MethodName = "test3", @Modifiers = 16, @Name = "test3", @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = true, @Strictfp = false, @Synchronized = false, @SyntacticallyAbstract = false, @SyntacticallyPublic = false, @Transient = false, @Void = true, @Volatile = false] | +- ResultType[@Void = true, @returnsArray = false] @@ -196,7 +196,7 @@ | | | +- Expression[@StandAlonePrimitive = false] | | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""String, including null"", @FloatLiteral = false, @Image = ""String, including null"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""String, including null"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"String, including null\"", @FloatLiteral = false, @Image = "\"String, including null\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"String, including null\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | +- BlockStatement[@Allocation = false] | | | +- Statement[] | | | +- BreakStatement[] @@ -213,7 +213,7 @@ | | | +- Expression[@StandAlonePrimitive = false] | | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""default case"", @FloatLiteral = false, @Image = ""default case"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""default case"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"default case\"", @FloatLiteral = false, @Image = "\"default case\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"default case\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | +- BlockStatement[@Allocation = false] | | +- Statement[] | | +- BreakStatement[] @@ -246,7 +246,7 @@ | | | +- Expression[@StandAlonePrimitive = false] | | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""String, including null"", @FloatLiteral = false, @Image = ""String, including null"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""String, including null"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"String, including null\"", @FloatLiteral = false, @Image = "\"String, including null\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"String, including null\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | +- SwitchLabeledExpression[] | | +- SwitchLabel[@Default = true] | | +- Expression[@StandAlonePrimitive = false] @@ -259,7 +259,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""default case"", @FloatLiteral = false, @Image = ""default case"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""default case"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"default case\"", @FloatLiteral = false, @Image = "\"default case\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"default case\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- BlockStatement[@Allocation = false] | | +- Statement[] | | +- SwitchStatement[@DefaultCase = true, @ExhaustiveEnumSwitch = false, @FallthroughSwitch = true] @@ -286,7 +286,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""The rest (including null)"", @FloatLiteral = false, @Image = ""The rest (including null)"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""The rest (including null)"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"The rest (including null)\"", @FloatLiteral = false, @Image = "\"The rest (including null)\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"The rest (including null)\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- BlockStatement[@Allocation = false] | +- Statement[] | +- SwitchStatement[@DefaultCase = true, @ExhaustiveEnumSwitch = false, @FallthroughSwitch = false] @@ -311,7 +311,7 @@ | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""The rest (including null)"", @FloatLiteral = false, @Image = ""The rest (including null)"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""The rest (including null)"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"The rest (including null)\"", @FloatLiteral = false, @Image = "\"The rest (including null)\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"The rest (including null)\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.METHOD] +- MethodDeclaration[@Abstract = false, @Arity = 1, @Default = false, @Final = false, @InterfaceMember = false, @Kind = MethodLikeKind.METHOD, @MethodName = "main", @Modifiers = 17, @Name = "main", @Native = false, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @Static = true, @Strictfp = false, @Synchronized = false, @SyntacticallyAbstract = false, @SyntacticallyPublic = true, @Transient = false, @Void = true, @Volatile = false] +- ResultType[@Void = true, @returnsArray = false] @@ -335,7 +335,7 @@ | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""test"", @FloatLiteral = false, @Image = ""test"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""test"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"test\"", @FloatLiteral = false, @Image = "\"test\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"test\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- BlockStatement[@Allocation = false] | +- Statement[] | +- StatementExpression[] @@ -412,7 +412,7 @@ | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""test"", @FloatLiteral = false, @Image = ""test"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""test"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"test\"", @FloatLiteral = false, @Image = "\"test\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"test\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- BlockStatement[@Allocation = false] +- Statement[] +- StatementExpression[] diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java17p/EnhancedTypeCheckingSwitch.txt b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java17p/EnhancedTypeCheckingSwitch.txt index d5ea56fdf2..15082ceb4e 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java17p/EnhancedTypeCheckingSwitch.txt +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java17p/EnhancedTypeCheckingSwitch.txt @@ -37,7 +37,7 @@ | | | +- Expression[@StandAlonePrimitive = false] | | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""null"", @FloatLiteral = false, @Image = ""null"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""null"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"null\"", @FloatLiteral = false, @Image = "\"null\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"null\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | +- SwitchLabeledExpression[] | | | +- SwitchLabel[@Default = false] | | | | +- TypePattern[@ParenthesisDepth = 0] @@ -55,7 +55,7 @@ | | | +- Expression[@StandAlonePrimitive = false] | | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""String"", @FloatLiteral = false, @Image = ""String"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""String"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"String\"", @FloatLiteral = false, @Image = "\"String\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"String\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | +- SwitchLabeledExpression[] | | | +- SwitchLabel[@Default = false] | | | | +- TypePattern[@ParenthesisDepth = 0] @@ -74,7 +74,7 @@ | | | +- AdditiveExpression[@Image = "+", @Operator = "+"] | | | +- PrimaryExpression[] | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""Color with "", @FloatLiteral = false, @Image = ""Color with "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""Color with "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Color with \"", @FloatLiteral = false, @Image = "\"Color with \"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Color with \"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | | +- PrimaryExpression[] | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] | | | | | +- Name[@Image = "c.values"] @@ -83,7 +83,7 @@ | | | | +- PrimarySuffix[@ArgumentCount = -1, @Arguments = false, @ArrayDereference = false, @Image = "length"] | | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "" values"", @FloatLiteral = false, @Image = "" values"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "" values"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\" values\"", @FloatLiteral = false, @Image = "\" values\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\" values\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | +- SwitchLabeledExpression[] | | | +- SwitchLabel[@Default = false] | | | | +- TypePattern[@ParenthesisDepth = 0] @@ -102,7 +102,7 @@ | | | +- AdditiveExpression[@Image = "+", @Operator = "+"] | | | +- PrimaryExpression[] | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""Record class: "", @FloatLiteral = false, @Image = ""Record class: "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""Record class: "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Record class: \"", @FloatLiteral = false, @Image = "\"Record class: \"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Record class: \"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] | | | | +- Name[@Image = "p.toString"] @@ -126,7 +126,7 @@ | | | +- AdditiveExpression[@Image = "+", @Operator = "+"] | | | +- PrimaryExpression[] | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""Array of ints of length"", @FloatLiteral = false, @Image = ""Array of ints of length"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""Array of ints of length"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Array of ints of length\"", @FloatLiteral = false, @Image = "\"Array of ints of length\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Array of ints of length\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] | | | +- Name[@Image = "ia.length"] @@ -142,7 +142,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""Something else"", @FloatLiteral = false, @Image = ""Something else"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""Something else"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Something else\"", @FloatLiteral = false, @Image = "\"Something else\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Something else\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.METHOD] | +- MethodDeclaration[@Abstract = false, @Arity = 1, @Default = false, @Final = false, @InterfaceMember = false, @Kind = MethodLikeKind.METHOD, @MethodName = "main", @Modifiers = 17, @Name = "main", @Native = false, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @Static = true, @Strictfp = false, @Synchronized = false, @SyntacticallyAbstract = false, @SyntacticallyPublic = true, @Transient = false, @Void = true, @Volatile = false] | +- ResultType[@Void = true, @returnsArray = false] @@ -165,7 +165,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""test"", @FloatLiteral = false, @Image = ""test"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""test"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"test\"", @FloatLiteral = false, @Image = "\"test\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"test\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- BlockStatement[@Allocation = false] | +- Statement[] | +- StatementExpression[] diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java17p/GuardedAndParenthesizedPatterns.txt b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java17p/GuardedAndParenthesizedPatterns.txt index 028f55ff39..833fd9b0e5 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java17p/GuardedAndParenthesizedPatterns.txt +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java17p/GuardedAndParenthesizedPatterns.txt @@ -50,7 +50,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""single char string"", @FloatLiteral = false, @Image = ""single char string"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""single char string"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"single char string\"", @FloatLiteral = false, @Image = "\"single char string\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"single char string\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- SwitchLabeledExpression[] | | +- SwitchLabel[@Default = false] | | | +- TypePattern[@ParenthesisDepth = 0] @@ -68,7 +68,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""string"", @FloatLiteral = false, @Image = ""string"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""string"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"string\"", @FloatLiteral = false, @Image = "\"string\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"string\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- SwitchLabeledExpression[] | | +- SwitchLabel[@Default = false] | | | +- GuardedPattern[@ParenthesisDepth = 1] @@ -96,7 +96,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""integer 1"", @FloatLiteral = false, @Image = ""integer 1"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""integer 1"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"integer 1\"", @FloatLiteral = false, @Image = "\"integer 1\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"integer 1\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- SwitchLabeledExpression[] | | +- SwitchLabel[@Default = false] | | | +- GuardedPattern[@ParenthesisDepth = 3] @@ -124,7 +124,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""long 1 with parens"", @FloatLiteral = false, @Image = ""long 1 with parens"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""long 1 with parens"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"long 1 with parens\"", @FloatLiteral = false, @Image = "\"long 1 with parens\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"long 1 with parens\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- SwitchLabeledExpression[] | | +- SwitchLabel[@Default = false] | | | +- TypePattern[@ParenthesisDepth = 3] @@ -142,7 +142,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""double with parens"", @FloatLiteral = false, @Image = ""double with parens"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""double with parens"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"double with parens\"", @FloatLiteral = false, @Image = "\"double with parens\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"double with parens\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- SwitchLabeledExpression[] | +- SwitchLabel[@Default = true] | +- Expression[@StandAlonePrimitive = false] @@ -155,7 +155,7 @@ | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""default case"", @FloatLiteral = false, @Image = ""default case"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""default case"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"default case\"", @FloatLiteral = false, @Image = "\"default case\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"default case\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.METHOD] | +- MethodDeclaration[@Abstract = false, @Arity = 1, @Default = false, @Final = false, @InterfaceMember = false, @Kind = MethodLikeKind.METHOD, @MethodName = "instanceOfPattern", @Modifiers = 16, @Name = "instanceOfPattern", @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = true, @Strictfp = false, @Synchronized = false, @SyntacticallyAbstract = false, @SyntacticallyPublic = false, @Transient = false, @Void = true, @Volatile = false] | +- ResultType[@Void = true, @returnsArray = false] @@ -204,7 +204,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""A string containing at least two characters"", @FloatLiteral = false, @Image = ""A string containing at least two characters"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""A string containing at least two characters"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"A string containing at least two characters\"", @FloatLiteral = false, @Image = "\"A string containing at least two characters\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"A string containing at least two characters\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- BlockStatement[@Allocation = false] | | +- Statement[] | | +- IfStatement[@Else = false] @@ -254,7 +254,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""A string containing at least three characters"", @FloatLiteral = false, @Image = ""A string containing at least three characters"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""A string containing at least three characters"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"A string containing at least three characters\"", @FloatLiteral = false, @Image = "\"A string containing at least three characters\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"A string containing at least three characters\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- BlockStatement[@Allocation = false] | +- Statement[] | +- IfStatement[@Else = false] @@ -292,7 +292,7 @@ | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""A string containing at least four characters"", @FloatLiteral = false, @Image = ""A string containing at least four characters"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""A string containing at least four characters"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"A string containing at least four characters\"", @FloatLiteral = false, @Image = "\"A string containing at least four characters\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"A string containing at least four characters\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.METHOD] +- MethodDeclaration[@Abstract = false, @Arity = 1, @Default = false, @Final = false, @InterfaceMember = false, @Kind = MethodLikeKind.METHOD, @MethodName = "main", @Modifiers = 17, @Name = "main", @Native = false, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @Static = true, @Strictfp = false, @Synchronized = false, @SyntacticallyAbstract = false, @SyntacticallyPublic = true, @Transient = false, @Void = true, @Volatile = false] +- ResultType[@Void = true, @returnsArray = false] @@ -316,7 +316,7 @@ | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""a"", @FloatLiteral = false, @Image = ""a"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = true, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""a"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"a\"", @FloatLiteral = false, @Image = "\"a\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = true, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"a\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- BlockStatement[@Allocation = false] | +- Statement[] | +- StatementExpression[] @@ -329,7 +329,7 @@ | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""fooo"", @FloatLiteral = false, @Image = ""fooo"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""fooo"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"fooo\"", @FloatLiteral = false, @Image = "\"fooo\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"fooo\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- BlockStatement[@Allocation = false] | +- Statement[] | +- StatementExpression[] @@ -368,7 +368,7 @@ | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""abcde"", @FloatLiteral = false, @Image = ""abcde"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""abcde"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"abcde\"", @FloatLiteral = false, @Image = "\"abcde\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"abcde\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- BlockStatement[@Allocation = false] +- Statement[] +- StatementExpression[] diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java17p/PatternsInSwitchLabels.txt b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java17p/PatternsInSwitchLabels.txt index c13492cb44..71557a780e 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java17p/PatternsInSwitchLabels.txt +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java17p/PatternsInSwitchLabels.txt @@ -56,7 +56,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""int %d"", @FloatLiteral = false, @Image = ""int %d"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""int %d"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"int %d\"", @FloatLiteral = false, @Image = "\"int %d\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"int %d\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] @@ -78,7 +78,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""long %d"", @FloatLiteral = false, @Image = ""long %d"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""long %d"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"long %d\"", @FloatLiteral = false, @Image = "\"long %d\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"long %d\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] @@ -100,7 +100,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""double %f"", @FloatLiteral = false, @Image = ""double %f"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""double %f"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"double %f\"", @FloatLiteral = false, @Image = "\"double %f\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"double %f\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] @@ -122,7 +122,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""String %s"", @FloatLiteral = false, @Image = ""String %s"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""String %s"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"String %s\"", @FloatLiteral = false, @Image = "\"String %s\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"String %s\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java17p/ScopeOfPatternVariableDeclarations.txt b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java17p/ScopeOfPatternVariableDeclarations.txt index 1a11900d39..e2d6b63390 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java17p/ScopeOfPatternVariableDeclarations.txt +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java17p/ScopeOfPatternVariableDeclarations.txt @@ -55,7 +55,7 @@ | | | +- Expression[@StandAlonePrimitive = false] | | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""Ding!"", @FloatLiteral = false, @Image = ""Ding!"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""Ding!"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Ding!\"", @FloatLiteral = false, @Image = "\"Ding!\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Ding!\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | +- BlockStatement[@Allocation = false] | | +- Statement[] | | +- StatementExpression[] @@ -68,7 +68,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""Character"", @FloatLiteral = false, @Image = ""Character"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""Character"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Character\"", @FloatLiteral = false, @Image = "\"Character\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Character\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- SwitchLabeledThrowStatement[] | | +- SwitchLabel[@Default = false] | | | +- TypePattern[@ParenthesisDepth = 0] @@ -88,7 +88,7 @@ | | +- AdditiveExpression[@Image = "+", @Operator = "+"] | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""Invalid Integer argument of value "", @FloatLiteral = false, @Image = ""Invalid Integer argument of value "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""Invalid Integer argument of value "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Invalid Integer argument of value \"", @FloatLiteral = false, @Image = "\"Invalid Integer argument of value \"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Invalid Integer argument of value \"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] | | | +- Name[@Image = "i.intValue"] @@ -151,7 +151,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""Ding "", @FloatLiteral = false, @Image = ""Ding "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""Ding "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Ding \"", @FloatLiteral = false, @Image = "\"Ding \"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Ding \"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- BlockStatement[@Allocation = false] | | +- Statement[] | | +- IfStatement[@Else = false] @@ -179,7 +179,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""Tab "", @FloatLiteral = false, @Image = ""Tab "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""Tab "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Tab \"", @FloatLiteral = false, @Image = "\"Tab \"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Tab \"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- BlockStatement[@Allocation = false] | | +- Statement[] | | +- StatementExpression[] @@ -192,7 +192,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""character"", @FloatLiteral = false, @Image = ""character"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""character"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"character\"", @FloatLiteral = false, @Image = "\"character\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"character\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- SwitchLabel[@Default = true] | +- BlockStatement[@Allocation = false] | +- Statement[] @@ -225,7 +225,7 @@ | +- Expression[@StandAlonePrimitive = true] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = true, @DoubleLiteral = false, @EscapedStringLiteral = "'A'", @FloatLiteral = false, @Image = "'A'", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = false, @TextBlock = false, @TextBlockContent = "'A'", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = true, @DoubleLiteral = false, @EscapedStringLiteral = "\'A\'", @FloatLiteral = false, @Image = "\'A\'", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = false, @TextBlock = false, @TextBlockContent = "\'A\'", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- BlockStatement[@Allocation = false] +- Statement[] +- StatementExpression[] @@ -238,4 +238,4 @@ +- Expression[@StandAlonePrimitive = true] +- PrimaryExpression[] +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - +- Literal[@CharLiteral = true, @DoubleLiteral = false, @EscapedStringLiteral = "' '", @FloatLiteral = false, @Image = "' '", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = false, @TextBlock = false, @TextBlockContent = "' '", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + +- Literal[@CharLiteral = true, @DoubleLiteral = false, @EscapedStringLiteral = "\'\\t\'", @FloatLiteral = false, @Image = "\'\\t\'", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = false, @TextBlock = false, @TextBlockContent = "\'\\t\'", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java18p/DealingWithNull.txt b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java18p/DealingWithNull.txt index 72878864b5..de92235cf5 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java18p/DealingWithNull.txt +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java18p/DealingWithNull.txt @@ -37,17 +37,17 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""Oops"", @FloatLiteral = false, @Image = ""Oops"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""Oops"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Oops\"", @FloatLiteral = false, @Image = "\"Oops\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Oops\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- SwitchLabeledExpression[] | | +- SwitchLabel[@Default = false] | | | +- Expression[@StandAlonePrimitive = false] | | | | +- PrimaryExpression[] | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""Foo"", @FloatLiteral = false, @Image = ""Foo"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""Foo"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Foo\"", @FloatLiteral = false, @Image = "\"Foo\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Foo\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | | +- Expression[@StandAlonePrimitive = false] | | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""Bar"", @FloatLiteral = false, @Image = ""Bar"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""Bar"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Bar\"", @FloatLiteral = false, @Image = "\"Bar\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Bar\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] @@ -58,7 +58,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""Great"", @FloatLiteral = false, @Image = ""Great"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""Great"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Great\"", @FloatLiteral = false, @Image = "\"Great\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Great\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- SwitchLabeledExpression[] | +- SwitchLabel[@Default = true] | +- Expression[@StandAlonePrimitive = false] @@ -71,7 +71,7 @@ | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""Ok"", @FloatLiteral = false, @Image = ""Ok"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""Ok"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Ok\"", @FloatLiteral = false, @Image = "\"Ok\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Ok\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.METHOD] | +- MethodDeclaration[@Abstract = false, @Arity = 1, @Default = false, @Final = false, @InterfaceMember = false, @Kind = MethodLikeKind.METHOD, @MethodName = "testStringOrNull", @Modifiers = 16, @Name = "testStringOrNull", @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = true, @Strictfp = false, @Synchronized = false, @SyntacticallyAbstract = false, @SyntacticallyPublic = false, @Transient = false, @Void = true, @Volatile = false] | +- ResultType[@Void = true, @returnsArray = false] @@ -113,7 +113,7 @@ | | +- AdditiveExpression[@Image = "+", @Operator = "+"] | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""String: "", @FloatLiteral = false, @Image = ""String: "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""String: "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"String: \"", @FloatLiteral = false, @Image = "\"String: \"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"String: \"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] | | +- Name[@Image = "s"] @@ -129,7 +129,7 @@ | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""default case"", @FloatLiteral = false, @Image = ""default case"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""default case"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"default case\"", @FloatLiteral = false, @Image = "\"default case\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"default case\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.METHOD] | +- MethodDeclaration[@Abstract = false, @Arity = 1, @Default = false, @Final = false, @InterfaceMember = false, @Kind = MethodLikeKind.METHOD, @MethodName = "test", @Modifiers = 16, @Name = "test", @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = true, @Strictfp = false, @Synchronized = false, @SyntacticallyAbstract = false, @SyntacticallyPublic = false, @Transient = false, @Void = true, @Volatile = false] | +- ResultType[@Void = true, @returnsArray = false] @@ -165,7 +165,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""null!"", @FloatLiteral = false, @Image = ""null!"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""null!"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"null!\"", @FloatLiteral = false, @Image = "\"null!\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"null!\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- SwitchLabeledExpression[] | | +- SwitchLabel[@Default = false] | | | +- TypePattern[@ParenthesisDepth = 0] @@ -183,7 +183,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""String"", @FloatLiteral = false, @Image = ""String"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""String"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"String\"", @FloatLiteral = false, @Image = "\"String\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"String\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- SwitchLabeledExpression[] | +- SwitchLabel[@Default = true] | +- Expression[@StandAlonePrimitive = false] @@ -196,7 +196,7 @@ | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""Something else"", @FloatLiteral = false, @Image = ""Something else"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""Something else"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Something else\"", @FloatLiteral = false, @Image = "\"Something else\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Something else\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.METHOD] | +- MethodDeclaration[@Abstract = false, @Arity = 1, @Default = false, @Final = false, @InterfaceMember = false, @Kind = MethodLikeKind.METHOD, @MethodName = "test2", @Modifiers = 16, @Name = "test2", @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = true, @Strictfp = false, @Synchronized = false, @SyntacticallyAbstract = false, @SyntacticallyPublic = false, @Transient = false, @Void = true, @Volatile = false] | +- ResultType[@Void = true, @returnsArray = false] @@ -247,7 +247,7 @@ | | +- AdditiveExpression[@Image = "+", @Operator = "+"] | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""String: "", @FloatLiteral = false, @Image = ""String: "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""String: "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"String: \"", @FloatLiteral = false, @Image = "\"String: \"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"String: \"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] | | +- Name[@Image = "s"] @@ -268,7 +268,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""Integer"", @FloatLiteral = false, @Image = ""Integer"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""Integer"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Integer\"", @FloatLiteral = false, @Image = "\"Integer\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Integer\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- SwitchLabeledExpression[] | +- SwitchLabel[@Default = true] | +- Expression[@StandAlonePrimitive = false] @@ -281,7 +281,7 @@ | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""default"", @FloatLiteral = false, @Image = ""default"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""default"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"default\"", @FloatLiteral = false, @Image = "\"default\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"default\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.METHOD] | +- MethodDeclaration[@Abstract = false, @Arity = 1, @Default = false, @Final = false, @InterfaceMember = false, @Kind = MethodLikeKind.METHOD, @MethodName = "test3", @Modifiers = 16, @Name = "test3", @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = true, @Strictfp = false, @Synchronized = false, @SyntacticallyAbstract = false, @SyntacticallyPublic = false, @Transient = false, @Void = true, @Volatile = false] | +- ResultType[@Void = true, @returnsArray = false] @@ -324,7 +324,7 @@ | | | +- Expression[@StandAlonePrimitive = false] | | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""String, including null"", @FloatLiteral = false, @Image = ""String, including null"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""String, including null"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"String, including null\"", @FloatLiteral = false, @Image = "\"String, including null\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"String, including null\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | +- BlockStatement[@Allocation = false] | | | +- Statement[] | | | +- BreakStatement[] @@ -341,7 +341,7 @@ | | | +- Expression[@StandAlonePrimitive = false] | | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""default case"", @FloatLiteral = false, @Image = ""default case"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""default case"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"default case\"", @FloatLiteral = false, @Image = "\"default case\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"default case\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | +- BlockStatement[@Allocation = false] | | +- Statement[] | | +- BreakStatement[] @@ -374,7 +374,7 @@ | | | +- Expression[@StandAlonePrimitive = false] | | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""String, including null"", @FloatLiteral = false, @Image = ""String, including null"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""String, including null"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"String, including null\"", @FloatLiteral = false, @Image = "\"String, including null\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"String, including null\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | +- SwitchLabeledExpression[] | | +- SwitchLabel[@Default = true] | | +- Expression[@StandAlonePrimitive = false] @@ -387,7 +387,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""default case"", @FloatLiteral = false, @Image = ""default case"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""default case"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"default case\"", @FloatLiteral = false, @Image = "\"default case\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"default case\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- BlockStatement[@Allocation = false] | | +- Statement[] | | +- SwitchStatement[@DefaultCase = true, @ExhaustiveEnumSwitch = false, @FallthroughSwitch = true] @@ -414,7 +414,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""The rest (including null)"", @FloatLiteral = false, @Image = ""The rest (including null)"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""The rest (including null)"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"The rest (including null)\"", @FloatLiteral = false, @Image = "\"The rest (including null)\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"The rest (including null)\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- BlockStatement[@Allocation = false] | +- Statement[] | +- SwitchStatement[@DefaultCase = true, @ExhaustiveEnumSwitch = false, @FallthroughSwitch = false] @@ -439,7 +439,7 @@ | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""The rest (including null)"", @FloatLiteral = false, @Image = ""The rest (including null)"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""The rest (including null)"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"The rest (including null)\"", @FloatLiteral = false, @Image = "\"The rest (including null)\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"The rest (including null)\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.METHOD] +- MethodDeclaration[@Abstract = false, @Arity = 1, @Default = false, @Final = false, @InterfaceMember = false, @Kind = MethodLikeKind.METHOD, @MethodName = "main", @Modifiers = 17, @Name = "main", @Native = false, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @Static = true, @Strictfp = false, @Synchronized = false, @SyntacticallyAbstract = false, @SyntacticallyPublic = true, @Transient = false, @Void = true, @Volatile = false] +- ResultType[@Void = true, @returnsArray = false] @@ -463,7 +463,7 @@ | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""test"", @FloatLiteral = false, @Image = ""test"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""test"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"test\"", @FloatLiteral = false, @Image = "\"test\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"test\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- BlockStatement[@Allocation = false] | +- Statement[] | +- StatementExpression[] @@ -540,7 +540,7 @@ | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""test"", @FloatLiteral = false, @Image = ""test"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""test"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"test\"", @FloatLiteral = false, @Image = "\"test\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"test\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- BlockStatement[@Allocation = false] | +- Statement[] | +- StatementExpression[] @@ -581,7 +581,7 @@ | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""Foo"", @FloatLiteral = false, @Image = ""Foo"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""Foo"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Foo\"", @FloatLiteral = false, @Image = "\"Foo\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Foo\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- BlockStatement[@Allocation = false] | +- Statement[] | +- StatementExpression[] @@ -594,7 +594,7 @@ | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""Bar"", @FloatLiteral = false, @Image = ""Bar"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""Bar"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Bar\"", @FloatLiteral = false, @Image = "\"Bar\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Bar\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- BlockStatement[@Allocation = false] | +- Statement[] | +- StatementExpression[] @@ -607,7 +607,7 @@ | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""baz"", @FloatLiteral = false, @Image = ""baz"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""baz"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"baz\"", @FloatLiteral = false, @Image = "\"baz\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"baz\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- BlockStatement[@Allocation = false] | +- Statement[] | +- StatementExpression[] @@ -634,4 +634,4 @@ +- Expression[@StandAlonePrimitive = false] +- PrimaryExpression[] +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""some string"", @FloatLiteral = false, @Image = ""some string"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""some string"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"some string\"", @FloatLiteral = false, @Image = "\"some string\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"some string\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java18p/EnhancedTypeCheckingSwitch.txt b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java18p/EnhancedTypeCheckingSwitch.txt index d5ea56fdf2..15082ceb4e 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java18p/EnhancedTypeCheckingSwitch.txt +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java18p/EnhancedTypeCheckingSwitch.txt @@ -37,7 +37,7 @@ | | | +- Expression[@StandAlonePrimitive = false] | | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""null"", @FloatLiteral = false, @Image = ""null"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""null"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"null\"", @FloatLiteral = false, @Image = "\"null\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"null\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | +- SwitchLabeledExpression[] | | | +- SwitchLabel[@Default = false] | | | | +- TypePattern[@ParenthesisDepth = 0] @@ -55,7 +55,7 @@ | | | +- Expression[@StandAlonePrimitive = false] | | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""String"", @FloatLiteral = false, @Image = ""String"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""String"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"String\"", @FloatLiteral = false, @Image = "\"String\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"String\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | +- SwitchLabeledExpression[] | | | +- SwitchLabel[@Default = false] | | | | +- TypePattern[@ParenthesisDepth = 0] @@ -74,7 +74,7 @@ | | | +- AdditiveExpression[@Image = "+", @Operator = "+"] | | | +- PrimaryExpression[] | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""Color with "", @FloatLiteral = false, @Image = ""Color with "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""Color with "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Color with \"", @FloatLiteral = false, @Image = "\"Color with \"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Color with \"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | | +- PrimaryExpression[] | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] | | | | | +- Name[@Image = "c.values"] @@ -83,7 +83,7 @@ | | | | +- PrimarySuffix[@ArgumentCount = -1, @Arguments = false, @ArrayDereference = false, @Image = "length"] | | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "" values"", @FloatLiteral = false, @Image = "" values"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "" values"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\" values\"", @FloatLiteral = false, @Image = "\" values\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\" values\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | +- SwitchLabeledExpression[] | | | +- SwitchLabel[@Default = false] | | | | +- TypePattern[@ParenthesisDepth = 0] @@ -102,7 +102,7 @@ | | | +- AdditiveExpression[@Image = "+", @Operator = "+"] | | | +- PrimaryExpression[] | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""Record class: "", @FloatLiteral = false, @Image = ""Record class: "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""Record class: "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Record class: \"", @FloatLiteral = false, @Image = "\"Record class: \"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Record class: \"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] | | | | +- Name[@Image = "p.toString"] @@ -126,7 +126,7 @@ | | | +- AdditiveExpression[@Image = "+", @Operator = "+"] | | | +- PrimaryExpression[] | | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""Array of ints of length"", @FloatLiteral = false, @Image = ""Array of ints of length"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""Array of ints of length"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Array of ints of length\"", @FloatLiteral = false, @Image = "\"Array of ints of length\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Array of ints of length\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] | | | +- Name[@Image = "ia.length"] @@ -142,7 +142,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""Something else"", @FloatLiteral = false, @Image = ""Something else"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""Something else"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Something else\"", @FloatLiteral = false, @Image = "\"Something else\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Something else\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.METHOD] | +- MethodDeclaration[@Abstract = false, @Arity = 1, @Default = false, @Final = false, @InterfaceMember = false, @Kind = MethodLikeKind.METHOD, @MethodName = "main", @Modifiers = 17, @Name = "main", @Native = false, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @Static = true, @Strictfp = false, @Synchronized = false, @SyntacticallyAbstract = false, @SyntacticallyPublic = true, @Transient = false, @Void = true, @Volatile = false] | +- ResultType[@Void = true, @returnsArray = false] @@ -165,7 +165,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""test"", @FloatLiteral = false, @Image = ""test"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""test"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"test\"", @FloatLiteral = false, @Image = "\"test\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"test\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- BlockStatement[@Allocation = false] | +- Statement[] | +- StatementExpression[] diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java18p/ExhaustiveSwitch.txt b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java18p/ExhaustiveSwitch.txt index ce57bb07ea..99203d9819 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java18p/ExhaustiveSwitch.txt +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java18p/ExhaustiveSwitch.txt @@ -112,7 +112,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""Integer"", @FloatLiteral = false, @Image = ""Integer"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""Integer"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Integer\"", @FloatLiteral = false, @Image = "\"Integer\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Integer\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- BlockStatement[@Allocation = false] | | +- Statement[] | | +- BreakStatement[] @@ -238,7 +238,7 @@ | | | +- Expression[@StandAlonePrimitive = false] | | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""A"", @FloatLiteral = false, @Image = ""A"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = true, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""A"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"A\"", @FloatLiteral = false, @Image = "\"A\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = true, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"A\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | +- BlockStatement[@Allocation = false] | | | +- Statement[] | | | +- BreakStatement[] @@ -260,7 +260,7 @@ | | | +- Expression[@StandAlonePrimitive = false] | | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""C"", @FloatLiteral = false, @Image = ""C"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = true, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""C"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"C\"", @FloatLiteral = false, @Image = "\"C\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = true, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"C\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | +- BlockStatement[@Allocation = false] | | | +- Statement[] | | | +- BreakStatement[] @@ -277,7 +277,7 @@ | | | +- Expression[@StandAlonePrimitive = false] | | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""default case, should be B"", @FloatLiteral = false, @Image = ""default case, should be B"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""default case, should be B"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"default case, should be B\"", @FloatLiteral = false, @Image = "\"default case, should be B\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"default case, should be B\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | +- BlockStatement[@Allocation = false] | | +- Statement[] | | +- BreakStatement[] @@ -385,7 +385,7 @@ | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""a string"", @FloatLiteral = false, @Image = ""a string"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""a string"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"a string\"", @FloatLiteral = false, @Image = "\"a string\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"a string\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- BlockStatement[@Allocation = false] | +- Statement[] | +- StatementExpression[] @@ -440,7 +440,7 @@ | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""a string"", @FloatLiteral = false, @Image = ""a string"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""a string"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"a string\"", @FloatLiteral = false, @Image = "\"a string\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"a string\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- BlockStatement[@Allocation = false] | +- Statement[] | +- StatementExpression[] @@ -482,7 +482,7 @@ | +- AdditiveExpression[@Image = "+", @Operator = "+"] | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""A:"", @FloatLiteral = false, @Image = ""A:"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""A:"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"A:\"", @FloatLiteral = false, @Image = "\"A:\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"A:\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] | | +- Name[@Image = "testSealedExhaustive"] @@ -508,7 +508,7 @@ | +- AdditiveExpression[@Image = "+", @Operator = "+"] | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""B:"", @FloatLiteral = false, @Image = ""B:"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""B:"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"B:\"", @FloatLiteral = false, @Image = "\"B:\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"B:\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] | | +- Name[@Image = "testSealedExhaustive"] @@ -534,7 +534,7 @@ | +- AdditiveExpression[@Image = "+", @Operator = "+"] | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""C:"", @FloatLiteral = false, @Image = ""C:"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""C:"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"C:\"", @FloatLiteral = false, @Image = "\"C:\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"C:\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] | | +- Name[@Image = "testSealedExhaustive"] @@ -615,7 +615,7 @@ +- AdditiveExpression[@Image = "+", @Operator = "+"] +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""F:"", @FloatLiteral = false, @Image = ""F:"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""F:"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"F:\"", @FloatLiteral = false, @Image = "\"F:\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"F:\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- PrimaryExpression[] +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] | +- Name[@Image = "testGenericSealedExhaustive"] diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java18p/GuardedAndParenthesizedPatterns.txt b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java18p/GuardedAndParenthesizedPatterns.txt index c9c3d0a1c5..c55afb51bf 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java18p/GuardedAndParenthesizedPatterns.txt +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java18p/GuardedAndParenthesizedPatterns.txt @@ -50,7 +50,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""single char string"", @FloatLiteral = false, @Image = ""single char string"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""single char string"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"single char string\"", @FloatLiteral = false, @Image = "\"single char string\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"single char string\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- SwitchLabeledExpression[] | | +- SwitchLabel[@Default = false] | | | +- TypePattern[@ParenthesisDepth = 0] @@ -68,7 +68,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""string"", @FloatLiteral = false, @Image = ""string"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""string"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"string\"", @FloatLiteral = false, @Image = "\"string\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"string\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- SwitchLabeledExpression[] | | +- SwitchLabel[@Default = false] | | | +- GuardedPattern[@ParenthesisDepth = 1] @@ -96,7 +96,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""integer 1"", @FloatLiteral = false, @Image = ""integer 1"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""integer 1"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"integer 1\"", @FloatLiteral = false, @Image = "\"integer 1\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"integer 1\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- SwitchLabeledExpression[] | | +- SwitchLabel[@Default = false] | | | +- GuardedPattern[@ParenthesisDepth = 3] @@ -124,7 +124,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""long 1 with parens"", @FloatLiteral = false, @Image = ""long 1 with parens"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""long 1 with parens"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"long 1 with parens\"", @FloatLiteral = false, @Image = "\"long 1 with parens\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"long 1 with parens\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- SwitchLabeledExpression[] | | +- SwitchLabel[@Default = false] | | | +- TypePattern[@ParenthesisDepth = 3] @@ -142,7 +142,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""double with parens"", @FloatLiteral = false, @Image = ""double with parens"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""double with parens"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"double with parens\"", @FloatLiteral = false, @Image = "\"double with parens\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"double with parens\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- SwitchLabeledExpression[] | +- SwitchLabel[@Default = true] | +- Expression[@StandAlonePrimitive = false] @@ -155,7 +155,7 @@ | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""default case"", @FloatLiteral = false, @Image = ""default case"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""default case"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"default case\"", @FloatLiteral = false, @Image = "\"default case\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"default case\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.METHOD] | +- MethodDeclaration[@Abstract = false, @Arity = 1, @Default = false, @Final = false, @InterfaceMember = false, @Kind = MethodLikeKind.METHOD, @MethodName = "testWithNull", @Modifiers = 16, @Name = "testWithNull", @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = true, @Strictfp = false, @Synchronized = false, @SyntacticallyAbstract = false, @SyntacticallyPublic = false, @Transient = false, @Void = true, @Volatile = false] | +- ResultType[@Void = true, @returnsArray = false] @@ -204,7 +204,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""single char string"", @FloatLiteral = false, @Image = ""single char string"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""single char string"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"single char string\"", @FloatLiteral = false, @Image = "\"single char string\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"single char string\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- SwitchLabeledExpression[] | | +- SwitchLabel[@Default = false] | | | +- TypePattern[@ParenthesisDepth = 0] @@ -222,7 +222,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""string"", @FloatLiteral = false, @Image = ""string"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""string"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"string\"", @FloatLiteral = false, @Image = "\"string\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"string\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- SwitchLabeledExpression[] | | +- SwitchLabel[@Default = false] | | | +- GuardedPattern[@ParenthesisDepth = 1] @@ -250,7 +250,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""integer 1"", @FloatLiteral = false, @Image = ""integer 1"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""integer 1"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"integer 1\"", @FloatLiteral = false, @Image = "\"integer 1\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"integer 1\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- SwitchLabeledExpression[] | | +- SwitchLabel[@Default = false] | | | +- GuardedPattern[@ParenthesisDepth = 3] @@ -278,7 +278,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""long 1 with parens"", @FloatLiteral = false, @Image = ""long 1 with parens"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""long 1 with parens"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"long 1 with parens\"", @FloatLiteral = false, @Image = "\"long 1 with parens\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"long 1 with parens\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- SwitchLabeledExpression[] | | +- SwitchLabel[@Default = false] | | | +- TypePattern[@ParenthesisDepth = 3] @@ -296,7 +296,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""double with parens"", @FloatLiteral = false, @Image = ""double with parens"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""double with parens"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"double with parens\"", @FloatLiteral = false, @Image = "\"double with parens\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"double with parens\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- SwitchLabeledExpression[] | | +- SwitchLabel[@Default = false] | | | +- Expression[@StandAlonePrimitive = false] @@ -314,7 +314,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""null!"", @FloatLiteral = false, @Image = ""null!"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""null!"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"null!\"", @FloatLiteral = false, @Image = "\"null!\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"null!\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- SwitchLabeledExpression[] | +- SwitchLabel[@Default = true] | +- Expression[@StandAlonePrimitive = false] @@ -327,7 +327,7 @@ | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""default case"", @FloatLiteral = false, @Image = ""default case"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""default case"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"default case\"", @FloatLiteral = false, @Image = "\"default case\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"default case\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.METHOD] | +- MethodDeclaration[@Abstract = false, @Arity = 1, @Default = false, @Final = false, @InterfaceMember = false, @Kind = MethodLikeKind.METHOD, @MethodName = "instanceOfPattern", @Modifiers = 16, @Name = "instanceOfPattern", @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = true, @Strictfp = false, @Synchronized = false, @SyntacticallyAbstract = false, @SyntacticallyPublic = false, @Transient = false, @Void = true, @Volatile = false] | +- ResultType[@Void = true, @returnsArray = false] @@ -376,7 +376,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""A string containing at least two characters"", @FloatLiteral = false, @Image = ""A string containing at least two characters"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""A string containing at least two characters"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"A string containing at least two characters\"", @FloatLiteral = false, @Image = "\"A string containing at least two characters\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"A string containing at least two characters\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- BlockStatement[@Allocation = false] | | +- Statement[] | | +- IfStatement[@Else = false] @@ -426,7 +426,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""A string containing at least three characters"", @FloatLiteral = false, @Image = ""A string containing at least three characters"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""A string containing at least three characters"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"A string containing at least three characters\"", @FloatLiteral = false, @Image = "\"A string containing at least three characters\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"A string containing at least three characters\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- BlockStatement[@Allocation = false] | +- Statement[] | +- IfStatement[@Else = false] @@ -464,7 +464,7 @@ | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""A string containing at least four characters"", @FloatLiteral = false, @Image = ""A string containing at least four characters"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""A string containing at least four characters"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"A string containing at least four characters\"", @FloatLiteral = false, @Image = "\"A string containing at least four characters\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"A string containing at least four characters\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.METHOD] +- MethodDeclaration[@Abstract = false, @Arity = 1, @Default = false, @Final = false, @InterfaceMember = false, @Kind = MethodLikeKind.METHOD, @MethodName = "main", @Modifiers = 17, @Name = "main", @Native = false, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @Static = true, @Strictfp = false, @Synchronized = false, @SyntacticallyAbstract = false, @SyntacticallyPublic = true, @Transient = false, @Void = true, @Volatile = false] +- ResultType[@Void = true, @returnsArray = false] @@ -488,7 +488,7 @@ | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""a"", @FloatLiteral = false, @Image = ""a"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = true, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""a"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"a\"", @FloatLiteral = false, @Image = "\"a\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = true, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"a\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- BlockStatement[@Allocation = false] | +- Statement[] | +- StatementExpression[] @@ -501,7 +501,7 @@ | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""fooo"", @FloatLiteral = false, @Image = ""fooo"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""fooo"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"fooo\"", @FloatLiteral = false, @Image = "\"fooo\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"fooo\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- BlockStatement[@Allocation = false] | +- Statement[] | +- StatementExpression[] @@ -540,7 +540,7 @@ | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""abcde"", @FloatLiteral = false, @Image = ""abcde"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""abcde"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"abcde\"", @FloatLiteral = false, @Image = "\"abcde\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"abcde\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- BlockStatement[@Allocation = false] | +- Statement[] | +- TryStatement[@Finally = false, @TryWithResources = false] diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java18p/PatternsInSwitchLabels.txt b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java18p/PatternsInSwitchLabels.txt index c13492cb44..71557a780e 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java18p/PatternsInSwitchLabels.txt +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java18p/PatternsInSwitchLabels.txt @@ -56,7 +56,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""int %d"", @FloatLiteral = false, @Image = ""int %d"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""int %d"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"int %d\"", @FloatLiteral = false, @Image = "\"int %d\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"int %d\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] @@ -78,7 +78,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""long %d"", @FloatLiteral = false, @Image = ""long %d"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""long %d"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"long %d\"", @FloatLiteral = false, @Image = "\"long %d\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"long %d\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] @@ -100,7 +100,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""double %f"", @FloatLiteral = false, @Image = ""double %f"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""double %f"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"double %f\"", @FloatLiteral = false, @Image = "\"double %f\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"double %f\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] @@ -122,7 +122,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""String %s"", @FloatLiteral = false, @Image = ""String %s"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""String %s"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"String %s\"", @FloatLiteral = false, @Image = "\"String %s\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"String %s\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java18p/RefiningPatternsInSwitch.txt b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java18p/RefiningPatternsInSwitch.txt index 87d4845579..8af1afb7bc 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java18p/RefiningPatternsInSwitch.txt +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java18p/RefiningPatternsInSwitch.txt @@ -114,7 +114,7 @@ | | | +- Expression[@StandAlonePrimitive = false] | | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""Large triangle"", @FloatLiteral = false, @Image = ""Large triangle"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""Large triangle"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Large triangle\"", @FloatLiteral = false, @Image = "\"Large triangle\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Large triangle\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | +- BlockStatement[@Allocation = false] | | +- Statement[] | | +- BreakStatement[] @@ -131,7 +131,7 @@ | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""A shape, possibly a small triangle"", @FloatLiteral = false, @Image = ""A shape, possibly a small triangle"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""A shape, possibly a small triangle"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"A shape, possibly a small triangle\"", @FloatLiteral = false, @Image = "\"A shape, possibly a small triangle\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"A shape, possibly a small triangle\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.METHOD] | +- MethodDeclaration[@Abstract = false, @Arity = 1, @Default = false, @Final = false, @InterfaceMember = false, @Kind = MethodLikeKind.METHOD, @MethodName = "testTriangleRefined", @Modifiers = 16, @Name = "testTriangleRefined", @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = true, @Strictfp = false, @Synchronized = false, @SyntacticallyAbstract = false, @SyntacticallyPublic = false, @Transient = false, @Void = true, @Volatile = false] | +- ResultType[@Void = true, @returnsArray = false] @@ -180,7 +180,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""Large triangle"", @FloatLiteral = false, @Image = ""Large triangle"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""Large triangle"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Large triangle\"", @FloatLiteral = false, @Image = "\"Large triangle\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Large triangle\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- SwitchLabeledExpression[] | +- SwitchLabel[@Default = true] | +- Expression[@StandAlonePrimitive = false] @@ -193,7 +193,7 @@ | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""A shape, possibly a small triangle"", @FloatLiteral = false, @Image = ""A shape, possibly a small triangle"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""A shape, possibly a small triangle"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"A shape, possibly a small triangle\"", @FloatLiteral = false, @Image = "\"A shape, possibly a small triangle\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"A shape, possibly a small triangle\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.METHOD] | +- MethodDeclaration[@Abstract = false, @Arity = 1, @Default = false, @Final = false, @InterfaceMember = false, @Kind = MethodLikeKind.METHOD, @MethodName = "testTriangleRefined2", @Modifiers = 16, @Name = "testTriangleRefined2", @Native = false, @PackagePrivate = true, @Private = false, @Protected = false, @Public = false, @Static = true, @Strictfp = false, @Synchronized = false, @SyntacticallyAbstract = false, @SyntacticallyPublic = false, @Transient = false, @Void = true, @Volatile = false] | +- ResultType[@Void = true, @returnsArray = false] @@ -242,7 +242,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""Large triangle"", @FloatLiteral = false, @Image = ""Large triangle"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""Large triangle"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Large triangle\"", @FloatLiteral = false, @Image = "\"Large triangle\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Large triangle\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- SwitchLabeledExpression[] | | +- SwitchLabel[@Default = false] | | | +- TypePattern[@ParenthesisDepth = 0] @@ -260,7 +260,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""Small triangle"", @FloatLiteral = false, @Image = ""Small triangle"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""Small triangle"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Small triangle\"", @FloatLiteral = false, @Image = "\"Small triangle\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Small triangle\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- SwitchLabeledExpression[] | +- SwitchLabel[@Default = true] | +- Expression[@StandAlonePrimitive = false] @@ -273,7 +273,7 @@ | +- Expression[@StandAlonePrimitive = false] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""Non-triangle"", @FloatLiteral = false, @Image = ""Non-triangle"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""Non-triangle"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Non-triangle\"", @FloatLiteral = false, @Image = "\"Non-triangle\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Non-triangle\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- ClassOrInterfaceBodyDeclaration[@AnonymousInnerClass = false, @EnumChild = false, @Kind = DeclarationKind.METHOD] +- MethodDeclaration[@Abstract = false, @Arity = 1, @Default = false, @Final = false, @InterfaceMember = false, @Kind = MethodLikeKind.METHOD, @MethodName = "main", @Modifiers = 17, @Name = "main", @Native = false, @PackagePrivate = false, @Private = false, @Protected = false, @Public = true, @Static = true, @Strictfp = false, @Synchronized = false, @SyntacticallyAbstract = false, @SyntacticallyPublic = true, @Transient = false, @Void = true, @Volatile = false] +- ResultType[@Void = true, @returnsArray = false] diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java18p/ScopeOfPatternVariableDeclarations.txt b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java18p/ScopeOfPatternVariableDeclarations.txt index 1a11900d39..e2d6b63390 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java18p/ScopeOfPatternVariableDeclarations.txt +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java18p/ScopeOfPatternVariableDeclarations.txt @@ -55,7 +55,7 @@ | | | +- Expression[@StandAlonePrimitive = false] | | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""Ding!"", @FloatLiteral = false, @Image = ""Ding!"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""Ding!"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Ding!\"", @FloatLiteral = false, @Image = "\"Ding!\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Ding!\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | +- BlockStatement[@Allocation = false] | | +- Statement[] | | +- StatementExpression[] @@ -68,7 +68,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""Character"", @FloatLiteral = false, @Image = ""Character"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""Character"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Character\"", @FloatLiteral = false, @Image = "\"Character\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Character\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- SwitchLabeledThrowStatement[] | | +- SwitchLabel[@Default = false] | | | +- TypePattern[@ParenthesisDepth = 0] @@ -88,7 +88,7 @@ | | +- AdditiveExpression[@Image = "+", @Operator = "+"] | | +- PrimaryExpression[] | | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""Invalid Integer argument of value "", @FloatLiteral = false, @Image = ""Invalid Integer argument of value "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""Invalid Integer argument of value "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Invalid Integer argument of value \"", @FloatLiteral = false, @Image = "\"Invalid Integer argument of value \"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Invalid Integer argument of value \"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] | | | +- Name[@Image = "i.intValue"] @@ -151,7 +151,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""Ding "", @FloatLiteral = false, @Image = ""Ding "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""Ding "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Ding \"", @FloatLiteral = false, @Image = "\"Ding \"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Ding \"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- BlockStatement[@Allocation = false] | | +- Statement[] | | +- IfStatement[@Else = false] @@ -179,7 +179,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""Tab "", @FloatLiteral = false, @Image = ""Tab "", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""Tab "", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"Tab \"", @FloatLiteral = false, @Image = "\"Tab \"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"Tab \"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- BlockStatement[@Allocation = false] | | +- Statement[] | | +- StatementExpression[] @@ -192,7 +192,7 @@ | | +- Expression[@StandAlonePrimitive = false] | | +- PrimaryExpression[] | | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = ""character"", @FloatLiteral = false, @Image = ""character"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = ""character"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | | +- Literal[@CharLiteral = false, @DoubleLiteral = false, @EscapedStringLiteral = "\"character\"", @FloatLiteral = false, @Image = "\"character\"", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = true, @TextBlock = false, @TextBlockContent = "\"character\"", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] | +- SwitchLabel[@Default = true] | +- BlockStatement[@Allocation = false] | +- Statement[] @@ -225,7 +225,7 @@ | +- Expression[@StandAlonePrimitive = true] | +- PrimaryExpression[] | +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - | +- Literal[@CharLiteral = true, @DoubleLiteral = false, @EscapedStringLiteral = "'A'", @FloatLiteral = false, @Image = "'A'", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = false, @TextBlock = false, @TextBlockContent = "'A'", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + | +- Literal[@CharLiteral = true, @DoubleLiteral = false, @EscapedStringLiteral = "\'A\'", @FloatLiteral = false, @Image = "\'A\'", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = false, @TextBlock = false, @TextBlockContent = "\'A\'", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] +- BlockStatement[@Allocation = false] +- Statement[] +- StatementExpression[] @@ -238,4 +238,4 @@ +- Expression[@StandAlonePrimitive = true] +- PrimaryExpression[] +- PrimaryPrefix[@SuperModifier = false, @ThisModifier = false] - +- Literal[@CharLiteral = true, @DoubleLiteral = false, @EscapedStringLiteral = "' '", @FloatLiteral = false, @Image = "' '", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = false, @TextBlock = false, @TextBlockContent = "' '", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] + +- Literal[@CharLiteral = true, @DoubleLiteral = false, @EscapedStringLiteral = "\'\\t\'", @FloatLiteral = false, @Image = "\'\\t\'", @IntLiteral = false, @LongLiteral = false, @SingleCharacterStringLiteral = false, @StringLiteral = false, @TextBlock = false, @TextBlockContent = "\'\\t\'", @ValueAsDouble = NaN, @ValueAsFloat = NaN, @ValueAsInt = 0, @ValueAsLong = 0] diff --git a/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/NodePrinters.kt b/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/NodePrinters.kt index c2b76c3a23..d1391bceb4 100644 --- a/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/NodePrinters.kt +++ b/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/NodePrinters.kt @@ -6,8 +6,8 @@ package net.sourceforge.pmd.lang.ast.test import net.sourceforge.pmd.lang.ast.Node import net.sourceforge.pmd.lang.ast.xpath.Attribute +import net.sourceforge.pmd.util.StringUtil import net.sourceforge.pmd.util.treeexport.TextTreeRenderer -import org.apache.commons.lang3.StringEscapeUtils /** * Prints just the structure, like so: @@ -33,35 +33,66 @@ open class RelevantAttributePrinter : BaseNodeAttributePrinter() { } +/** + * Only prints the begin/end coordinates. + */ +object CoordinatesPrinter : BaseNodeAttributePrinter() { + + private val Considered = setOf("BeginLine", "EndLine", "BeginColumn", "EndColumn") + + override fun fillAttributes(node: Node, result: MutableList) { + result += AttributeInfo("BeginLine", node.beginLine) + result += AttributeInfo("EndLine", node.endLine) + result += AttributeInfo("EndColumn", node.endColumn) + result += AttributeInfo("BeginColumn", node.beginColumn) + } + + override fun ignoreAttribute(node: Node, attribute: Attribute): Boolean = + attribute.name !in Considered + +} + /** * Base attribute printer, subclass to filter attributes. */ open class BaseNodeAttributePrinter : TextTreeRenderer(true, -1) { + data class AttributeInfo(val name: String, val value: Any?) + protected open fun ignoreAttribute(node: Node, attribute: Attribute): Boolean = true + protected open fun fillAttributes(node: Node, result: MutableList) { + node.xPathAttributesIterator + .asSequence() + .filterNot { ignoreAttribute(node, it) } + .map { AttributeInfo(it.name, it.value) } + .forEach { result += it } + } + + override fun appendNodeInfoLn(out: Appendable, node: Node) { out.append(node.xPathNodeName) - node.xPathAttributesIterator - .asSequence() - // sort to get deterministic results - .sortedBy { it.name } - .filterNot { ignoreAttribute(node, it) } - .joinTo(buffer = out, prefix = "[", postfix = "]") { - "@${it.name} = ${valueToString(it.value)}" - } + val attrs = mutableListOf().also { fillAttributes(node, it) } + + // sort to get deterministic results + attrs.sortBy { it.name } + + attrs.joinTo(buffer = out, prefix = "[", postfix = "]") { + "@${it.name} = ${valueToString(it.value)}" + } out.append("\n") } protected open fun valueToString(value: Any?): String? { return when (value) { - is String -> "\"" + StringEscapeUtils.unescapeJava(value) + "\"" + is String -> "\"" + StringUtil.escapeJava(value) + "\"" is Char -> '\''.toString() + value.toString().replace("'".toRegex(), "\\'") + '\''.toString() is Enum<*> -> value.enumDeclaringClass.simpleName + "." + value.name is Class<*> -> value.canonicalName?.let { "$it.class" } - is Number, is Boolean, null -> value.toString() + is Number, is Boolean -> value.toString() + null -> "null" else -> null } } diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect1.txt b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect1.txt index 6c18018e50..66c85d1839 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect1.txt +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect1.txt @@ -1,23 +1,4 @@ -+- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0, @Sourcecode = "-- --- BSD-style license; for more info see http://pmd.sourceforge.net/license.html --- - -CREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS - -- - TYPE t_data IS TABLE OF dual%ROWTYPE INDEX BY BINARY_INTEGER; - -- - l_data t_data; - l_sql VARCHAR2(500); - -- -BEGIN - -- - l_sql := 'SELECT * FROM DUAL'; - -- - EXECUTE IMMEDIATE l_sql BULK COLLECT - INTO l_data; - -- -END EXAMPLE_PROCEDURE; -"] ++- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0, @Sourcecode = "--\n-- BSD-style license; for more info see http://pmd.sourceforge.net/license.html\n--\n\nCREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS\n --\n TYPE t_data IS TABLE OF dual%ROWTYPE INDEX BY BINARY_INTEGER;\n --\n l_data t_data;\n l_sql VARCHAR2(500);\n --\nBEGIN\n --\n l_sql := \'SELECT * FROM DUAL\';\n --\n EXECUTE IMMEDIATE l_sql BULK COLLECT\n INTO l_data;\n --\nEND EXAMPLE_PROCEDURE;\n"] +- Global[@CanonicalImage = null] +- ProgramUnit[@CanonicalImage = null, @MethodName = "EXAMPLE_PROCEDURE", @Name = "EXAMPLE_PROCEDURE", @ObjectName = null] +- MethodDeclarator[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE", @ParameterCount = 1] @@ -50,16 +31,16 @@ END EXAMPLE_PROCEDURE; | +- NumericLiteral[@CanonicalImage = "500", @Image = "500"] +- Statement[@CanonicalImage = null] | +- UnlabelledStatement[@CanonicalImage = null] - | +- Expression[@CanonicalImage = "L_SQL := 'SELECT * FROM DUAL'", @Image = "l_sql := 'SELECT * FROM DUAL'"] - | +- Assignment[@CanonicalImage = "L_SQL := 'SELECT * FROM DUAL'", @Image = "l_sql := 'SELECT * FROM DUAL'"] + | +- Expression[@CanonicalImage = "L_SQL := \'SELECT * FROM DUAL\'", @Image = "l_sql := \'SELECT * FROM DUAL\'"] + | +- Assignment[@CanonicalImage = "L_SQL := \'SELECT * FROM DUAL\'", @Image = "l_sql := \'SELECT * FROM DUAL\'"] | +- PrimaryPrefix[@CanonicalImage = "L_SQL", @Image = "l_sql", @SelfModifier = false] | | +- SimpleExpression[@CanonicalImage = "L_SQL", @Image = "l_sql"] | | +- Column[@CanonicalImage = "L_SQL", @Image = "l_sql"] | | +- ID[@CanonicalImage = "L_SQL", @Image = "l_sql"] - | +- Expression[@CanonicalImage = "'SELECT * FROM DUAL'", @Image = "'SELECT * FROM DUAL'"] - | +- PrimaryPrefix[@CanonicalImage = "'SELECT * FROM DUAL'", @Image = "'SELECT * FROM DUAL'", @SelfModifier = false] - | +- Literal[@CanonicalImage = "'SELECT * FROM DUAL'", @Image = "'SELECT * FROM DUAL'"] - | +- StringLiteral[@CanonicalImage = "'SELECT * FROM DUAL'", @Image = "'SELECT * FROM DUAL'", @String = "SELECT * FROM DUAL"] + | +- Expression[@CanonicalImage = "\'SELECT * FROM DUAL\'", @Image = "\'SELECT * FROM DUAL\'"] + | +- PrimaryPrefix[@CanonicalImage = "\'SELECT * FROM DUAL\'", @Image = "\'SELECT * FROM DUAL\'", @SelfModifier = false] + | +- Literal[@CanonicalImage = "\'SELECT * FROM DUAL\'", @Image = "\'SELECT * FROM DUAL\'"] + | +- StringLiteral[@CanonicalImage = "\'SELECT * FROM DUAL\'", @Image = "\'SELECT * FROM DUAL\'", @String = "SELECT * FROM DUAL"] +- Statement[@CanonicalImage = null] | +- UnlabelledStatement[@CanonicalImage = null] | +- EmbeddedSqlStatement[@CanonicalImage = null] diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect2.txt b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect2.txt index 379336f71f..8965dd564c 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect2.txt +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect2.txt @@ -1,34 +1,4 @@ -+- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0, @Sourcecode = "-- --- BSD-style license; for more info see http://pmd.sourceforge.net/license.html --- - -CREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS - -- - TYPE t_data_key IS TABLE OF NUMBER INDEX BY BINARY_INTEGER; - TYPE t_data_description IS TABLE OF VARCHAR2(100) INDEX BY BINARY_INTEGER; - -- - l_data_key t_data_key; - l_data_description t_data_description; - l_sql VARCHAR2(500); - p_rownum1 NUMBER(20); - p_rownum2 NUMBER(20); - -- -BEGIN - -- - p_rownum1 := 10; - p_rownum2 := 30; - -- - l_sql := 'SELECT 1, ' || CHR(39) || 'First key' || CHR(39) || - ' FROM DUAL '||' WHERE ROWNUM <= :p_rownum1 ' || - 'UNION ALL '|| - 'SELECT 2, ' || CHR(39) || 'Second key ' || CHR(39) || - ' FROM DUAL'||' WHERE ROWNUM <= :p_rownum2 '; - -- - EXECUTE IMMEDIATE l_sql BULK COLLECT - INTO l_data_key, l_data_description USING p_rownum1, p_rownum2; - -- -END EXAMPLE_PROCEDURE; -"] ++- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0, @Sourcecode = "--\n-- BSD-style license; for more info see http://pmd.sourceforge.net/license.html\n--\n\nCREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS\n --\n TYPE t_data_key IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;\n TYPE t_data_description IS TABLE OF VARCHAR2(100) INDEX BY BINARY_INTEGER;\n --\n l_data_key t_data_key;\n l_data_description t_data_description;\n l_sql VARCHAR2(500);\n p_rownum1 NUMBER(20);\n p_rownum2 NUMBER(20);\n --\nBEGIN\n --\n p_rownum1 := 10;\n p_rownum2 := 30;\n --\n l_sql := \'SELECT 1, \' || CHR(39) || \'First key\' || CHR(39) || \n \' FROM DUAL \'||\' WHERE ROWNUM <= :p_rownum1 \' ||\n \'UNION ALL \'||\n \'SELECT 2, \' || CHR(39) || \'Second key \' || CHR(39) || \n \' FROM DUAL\'||\' WHERE ROWNUM <= :p_rownum2 \';\n --\n EXECUTE IMMEDIATE l_sql BULK COLLECT\n INTO l_data_key, l_data_description USING p_rownum1, p_rownum2;\n --\nEND EXAMPLE_PROCEDURE;\n"] +- Global[@CanonicalImage = null] +- ProgramUnit[@CanonicalImage = null, @MethodName = "EXAMPLE_PROCEDURE", @Name = "EXAMPLE_PROCEDURE", @ObjectName = null] +- MethodDeclarator[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE", @ParameterCount = 1] @@ -116,17 +86,17 @@ END EXAMPLE_PROCEDURE; | +- NumericLiteral[@CanonicalImage = "30", @Image = "30"] +- Statement[@CanonicalImage = null] | +- UnlabelledStatement[@CanonicalImage = null] - | +- Expression[@CanonicalImage = "L_SQL := 'SELECT 1, ' || CHR || 'FIRST KEY' || CHR || ' FROM DUAL ' || ' WHERE ROWNUM <= :P_ROWNUM1 ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'SECOND KEY ' || CHR || ' FROM DUAL' || ' WHERE ROWNUM <= :P_ROWNUM2 '", @Image = "l_sql := 'SELECT 1, ' || CHR || 'First key' || CHR || ' FROM DUAL ' || ' WHERE ROWNUM <= :p_rownum1 ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'Second key ' || CHR || ' FROM DUAL' || ' WHERE ROWNUM <= :p_rownum2 '"] - | +- Assignment[@CanonicalImage = "L_SQL := 'SELECT 1, ' || CHR || 'FIRST KEY' || CHR || ' FROM DUAL ' || ' WHERE ROWNUM <= :P_ROWNUM1 ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'SECOND KEY ' || CHR || ' FROM DUAL' || ' WHERE ROWNUM <= :P_ROWNUM2 '", @Image = "l_sql := 'SELECT 1, ' || CHR || 'First key' || CHR || ' FROM DUAL ' || ' WHERE ROWNUM <= :p_rownum1 ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'Second key ' || CHR || ' FROM DUAL' || ' WHERE ROWNUM <= :p_rownum2 '"] + | +- Expression[@CanonicalImage = "L_SQL := \'SELECT 1, \' || CHR || \'FIRST KEY\' || CHR || \' FROM DUAL \' || \' WHERE ROWNUM <= :P_ROWNUM1 \' || \'UNION ALL \' || \'SELECT 2, \' || CHR || \'SECOND KEY \' || CHR || \' FROM DUAL\' || \' WHERE ROWNUM <= :P_ROWNUM2 \'", @Image = "l_sql := \'SELECT 1, \' || CHR || \'First key\' || CHR || \' FROM DUAL \' || \' WHERE ROWNUM <= :p_rownum1 \' || \'UNION ALL \' || \'SELECT 2, \' || CHR || \'Second key \' || CHR || \' FROM DUAL\' || \' WHERE ROWNUM <= :p_rownum2 \'"] + | +- Assignment[@CanonicalImage = "L_SQL := \'SELECT 1, \' || CHR || \'FIRST KEY\' || CHR || \' FROM DUAL \' || \' WHERE ROWNUM <= :P_ROWNUM1 \' || \'UNION ALL \' || \'SELECT 2, \' || CHR || \'SECOND KEY \' || CHR || \' FROM DUAL\' || \' WHERE ROWNUM <= :P_ROWNUM2 \'", @Image = "l_sql := \'SELECT 1, \' || CHR || \'First key\' || CHR || \' FROM DUAL \' || \' WHERE ROWNUM <= :p_rownum1 \' || \'UNION ALL \' || \'SELECT 2, \' || CHR || \'Second key \' || CHR || \' FROM DUAL\' || \' WHERE ROWNUM <= :p_rownum2 \'"] | +- PrimaryPrefix[@CanonicalImage = "L_SQL", @Image = "l_sql", @SelfModifier = false] | | +- SimpleExpression[@CanonicalImage = "L_SQL", @Image = "l_sql"] | | +- Column[@CanonicalImage = "L_SQL", @Image = "l_sql"] | | +- ID[@CanonicalImage = "L_SQL", @Image = "l_sql"] - | +- Expression[@CanonicalImage = "'SELECT 1, ' || CHR || 'FIRST KEY' || CHR || ' FROM DUAL ' || ' WHERE ROWNUM <= :P_ROWNUM1 ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'SECOND KEY ' || CHR || ' FROM DUAL' || ' WHERE ROWNUM <= :P_ROWNUM2 '", @Image = "'SELECT 1, ' || CHR || 'First key' || CHR || ' FROM DUAL ' || ' WHERE ROWNUM <= :p_rownum1 ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'Second key ' || CHR || ' FROM DUAL' || ' WHERE ROWNUM <= :p_rownum2 '"] - | +- AdditiveExpression[@CanonicalImage = "'SELECT 1, ' || CHR || 'FIRST KEY' || CHR || ' FROM DUAL ' || ' WHERE ROWNUM <= :P_ROWNUM1 ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'SECOND KEY ' || CHR || ' FROM DUAL' || ' WHERE ROWNUM <= :P_ROWNUM2 '", @Image = "'SELECT 1, ' || CHR || 'First key' || CHR || ' FROM DUAL ' || ' WHERE ROWNUM <= :p_rownum1 ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'Second key ' || CHR || ' FROM DUAL' || ' WHERE ROWNUM <= :p_rownum2 '"] - | +- PrimaryPrefix[@CanonicalImage = "'SELECT 1, '", @Image = "'SELECT 1, '", @SelfModifier = false] - | | +- Literal[@CanonicalImage = "'SELECT 1, '", @Image = "'SELECT 1, '"] - | | +- StringLiteral[@CanonicalImage = "'SELECT 1, '", @Image = "'SELECT 1, '", @String = "SELECT 1, "] + | +- Expression[@CanonicalImage = "\'SELECT 1, \' || CHR || \'FIRST KEY\' || CHR || \' FROM DUAL \' || \' WHERE ROWNUM <= :P_ROWNUM1 \' || \'UNION ALL \' || \'SELECT 2, \' || CHR || \'SECOND KEY \' || CHR || \' FROM DUAL\' || \' WHERE ROWNUM <= :P_ROWNUM2 \'", @Image = "\'SELECT 1, \' || CHR || \'First key\' || CHR || \' FROM DUAL \' || \' WHERE ROWNUM <= :p_rownum1 \' || \'UNION ALL \' || \'SELECT 2, \' || CHR || \'Second key \' || CHR || \' FROM DUAL\' || \' WHERE ROWNUM <= :p_rownum2 \'"] + | +- AdditiveExpression[@CanonicalImage = "\'SELECT 1, \' || CHR || \'FIRST KEY\' || CHR || \' FROM DUAL \' || \' WHERE ROWNUM <= :P_ROWNUM1 \' || \'UNION ALL \' || \'SELECT 2, \' || CHR || \'SECOND KEY \' || CHR || \' FROM DUAL\' || \' WHERE ROWNUM <= :P_ROWNUM2 \'", @Image = "\'SELECT 1, \' || CHR || \'First key\' || CHR || \' FROM DUAL \' || \' WHERE ROWNUM <= :p_rownum1 \' || \'UNION ALL \' || \'SELECT 2, \' || CHR || \'Second key \' || CHR || \' FROM DUAL\' || \' WHERE ROWNUM <= :p_rownum2 \'"] + | +- PrimaryPrefix[@CanonicalImage = "\'SELECT 1, \'", @Image = "\'SELECT 1, \'", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "\'SELECT 1, \'", @Image = "\'SELECT 1, \'"] + | | +- StringLiteral[@CanonicalImage = "\'SELECT 1, \'", @Image = "\'SELECT 1, \'", @String = "SELECT 1, "] | +- PrimaryPrefix[@CanonicalImage = "CHR", @Image = "CHR", @SelfModifier = false] | | +- FunctionCall[@CanonicalImage = "CHR", @Image = "CHR"] | | +- FunctionName[@CanonicalImage = "CHR", @Image = "CHR"] @@ -138,9 +108,9 @@ END EXAMPLE_PROCEDURE; | | +- PrimaryPrefix[@CanonicalImage = "39", @Image = "39", @SelfModifier = false] | | +- Literal[@CanonicalImage = "39", @Image = "39"] | | +- NumericLiteral[@CanonicalImage = "39", @Image = "39"] - | +- PrimaryPrefix[@CanonicalImage = "'FIRST KEY'", @Image = "'First key'", @SelfModifier = false] - | | +- Literal[@CanonicalImage = "'FIRST KEY'", @Image = "'First key'"] - | | +- StringLiteral[@CanonicalImage = "'FIRST KEY'", @Image = "'First key'", @String = "First key"] + | +- PrimaryPrefix[@CanonicalImage = "\'FIRST KEY\'", @Image = "\'First key\'", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "\'FIRST KEY\'", @Image = "\'First key\'"] + | | +- StringLiteral[@CanonicalImage = "\'FIRST KEY\'", @Image = "\'First key\'", @String = "First key"] | +- PrimaryPrefix[@CanonicalImage = "CHR", @Image = "CHR", @SelfModifier = false] | | +- FunctionCall[@CanonicalImage = "CHR", @Image = "CHR"] | | +- FunctionName[@CanonicalImage = "CHR", @Image = "CHR"] @@ -152,18 +122,18 @@ END EXAMPLE_PROCEDURE; | | +- PrimaryPrefix[@CanonicalImage = "39", @Image = "39", @SelfModifier = false] | | +- Literal[@CanonicalImage = "39", @Image = "39"] | | +- NumericLiteral[@CanonicalImage = "39", @Image = "39"] - | +- PrimaryPrefix[@CanonicalImage = "' FROM DUAL '", @Image = "' FROM DUAL '", @SelfModifier = false] - | | +- Literal[@CanonicalImage = "' FROM DUAL '", @Image = "' FROM DUAL '"] - | | +- StringLiteral[@CanonicalImage = "' FROM DUAL '", @Image = "' FROM DUAL '", @String = " FROM DUAL "] - | +- PrimaryPrefix[@CanonicalImage = "' WHERE ROWNUM <= :P_ROWNUM1 '", @Image = "' WHERE ROWNUM <= :p_rownum1 '", @SelfModifier = false] - | | +- Literal[@CanonicalImage = "' WHERE ROWNUM <= :P_ROWNUM1 '", @Image = "' WHERE ROWNUM <= :p_rownum1 '"] - | | +- StringLiteral[@CanonicalImage = "' WHERE ROWNUM <= :P_ROWNUM1 '", @Image = "' WHERE ROWNUM <= :p_rownum1 '", @String = " WHERE ROWNUM <= :p_rownum1 "] - | +- PrimaryPrefix[@CanonicalImage = "'UNION ALL '", @Image = "'UNION ALL '", @SelfModifier = false] - | | +- Literal[@CanonicalImage = "'UNION ALL '", @Image = "'UNION ALL '"] - | | +- StringLiteral[@CanonicalImage = "'UNION ALL '", @Image = "'UNION ALL '", @String = "UNION ALL "] - | +- PrimaryPrefix[@CanonicalImage = "'SELECT 2, '", @Image = "'SELECT 2, '", @SelfModifier = false] - | | +- Literal[@CanonicalImage = "'SELECT 2, '", @Image = "'SELECT 2, '"] - | | +- StringLiteral[@CanonicalImage = "'SELECT 2, '", @Image = "'SELECT 2, '", @String = "SELECT 2, "] + | +- PrimaryPrefix[@CanonicalImage = "\' FROM DUAL \'", @Image = "\' FROM DUAL \'", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "\' FROM DUAL \'", @Image = "\' FROM DUAL \'"] + | | +- StringLiteral[@CanonicalImage = "\' FROM DUAL \'", @Image = "\' FROM DUAL \'", @String = " FROM DUAL "] + | +- PrimaryPrefix[@CanonicalImage = "\' WHERE ROWNUM <= :P_ROWNUM1 \'", @Image = "\' WHERE ROWNUM <= :p_rownum1 \'", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "\' WHERE ROWNUM <= :P_ROWNUM1 \'", @Image = "\' WHERE ROWNUM <= :p_rownum1 \'"] + | | +- StringLiteral[@CanonicalImage = "\' WHERE ROWNUM <= :P_ROWNUM1 \'", @Image = "\' WHERE ROWNUM <= :p_rownum1 \'", @String = " WHERE ROWNUM <= :p_rownum1 "] + | +- PrimaryPrefix[@CanonicalImage = "\'UNION ALL \'", @Image = "\'UNION ALL \'", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "\'UNION ALL \'", @Image = "\'UNION ALL \'"] + | | +- StringLiteral[@CanonicalImage = "\'UNION ALL \'", @Image = "\'UNION ALL \'", @String = "UNION ALL "] + | +- PrimaryPrefix[@CanonicalImage = "\'SELECT 2, \'", @Image = "\'SELECT 2, \'", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "\'SELECT 2, \'", @Image = "\'SELECT 2, \'"] + | | +- StringLiteral[@CanonicalImage = "\'SELECT 2, \'", @Image = "\'SELECT 2, \'", @String = "SELECT 2, "] | +- PrimaryPrefix[@CanonicalImage = "CHR", @Image = "CHR", @SelfModifier = false] | | +- FunctionCall[@CanonicalImage = "CHR", @Image = "CHR"] | | +- FunctionName[@CanonicalImage = "CHR", @Image = "CHR"] @@ -175,9 +145,9 @@ END EXAMPLE_PROCEDURE; | | +- PrimaryPrefix[@CanonicalImage = "39", @Image = "39", @SelfModifier = false] | | +- Literal[@CanonicalImage = "39", @Image = "39"] | | +- NumericLiteral[@CanonicalImage = "39", @Image = "39"] - | +- PrimaryPrefix[@CanonicalImage = "'SECOND KEY '", @Image = "'Second key '", @SelfModifier = false] - | | +- Literal[@CanonicalImage = "'SECOND KEY '", @Image = "'Second key '"] - | | +- StringLiteral[@CanonicalImage = "'SECOND KEY '", @Image = "'Second key '", @String = "Second key "] + | +- PrimaryPrefix[@CanonicalImage = "\'SECOND KEY \'", @Image = "\'Second key \'", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "\'SECOND KEY \'", @Image = "\'Second key \'"] + | | +- StringLiteral[@CanonicalImage = "\'SECOND KEY \'", @Image = "\'Second key \'", @String = "Second key "] | +- PrimaryPrefix[@CanonicalImage = "CHR", @Image = "CHR", @SelfModifier = false] | | +- FunctionCall[@CanonicalImage = "CHR", @Image = "CHR"] | | +- FunctionName[@CanonicalImage = "CHR", @Image = "CHR"] @@ -189,12 +159,12 @@ END EXAMPLE_PROCEDURE; | | +- PrimaryPrefix[@CanonicalImage = "39", @Image = "39", @SelfModifier = false] | | +- Literal[@CanonicalImage = "39", @Image = "39"] | | +- NumericLiteral[@CanonicalImage = "39", @Image = "39"] - | +- PrimaryPrefix[@CanonicalImage = "' FROM DUAL'", @Image = "' FROM DUAL'", @SelfModifier = false] - | | +- Literal[@CanonicalImage = "' FROM DUAL'", @Image = "' FROM DUAL'"] - | | +- StringLiteral[@CanonicalImage = "' FROM DUAL'", @Image = "' FROM DUAL'", @String = " FROM DUAL"] - | +- PrimaryPrefix[@CanonicalImage = "' WHERE ROWNUM <= :P_ROWNUM2 '", @Image = "' WHERE ROWNUM <= :p_rownum2 '", @SelfModifier = false] - | +- Literal[@CanonicalImage = "' WHERE ROWNUM <= :P_ROWNUM2 '", @Image = "' WHERE ROWNUM <= :p_rownum2 '"] - | +- StringLiteral[@CanonicalImage = "' WHERE ROWNUM <= :P_ROWNUM2 '", @Image = "' WHERE ROWNUM <= :p_rownum2 '", @String = " WHERE ROWNUM <= :p_rownum2 "] + | +- PrimaryPrefix[@CanonicalImage = "\' FROM DUAL\'", @Image = "\' FROM DUAL\'", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "\' FROM DUAL\'", @Image = "\' FROM DUAL\'"] + | | +- StringLiteral[@CanonicalImage = "\' FROM DUAL\'", @Image = "\' FROM DUAL\'", @String = " FROM DUAL"] + | +- PrimaryPrefix[@CanonicalImage = "\' WHERE ROWNUM <= :P_ROWNUM2 \'", @Image = "\' WHERE ROWNUM <= :p_rownum2 \'", @SelfModifier = false] + | +- Literal[@CanonicalImage = "\' WHERE ROWNUM <= :P_ROWNUM2 \'", @Image = "\' WHERE ROWNUM <= :p_rownum2 \'"] + | +- StringLiteral[@CanonicalImage = "\' WHERE ROWNUM <= :P_ROWNUM2 \'", @Image = "\' WHERE ROWNUM <= :p_rownum2 \'", @String = " WHERE ROWNUM <= :p_rownum2 "] +- Statement[@CanonicalImage = null] | +- UnlabelledStatement[@CanonicalImage = null] | +- EmbeddedSqlStatement[@CanonicalImage = null] diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect3.txt b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect3.txt index f8d384e4c9..14ea63e5da 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect3.txt +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect3.txt @@ -1,29 +1,4 @@ -+- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0, @Sourcecode = "-- --- BSD-style license; for more info see http://pmd.sourceforge.net/license.html --- - -CREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS - -- - TYPE t_data_key IS TABLE OF NUMBER INDEX BY BINARY_INTEGER; - TYPE t_data_description IS TABLE OF VARCHAR2(100) INDEX BY BINARY_INTEGER; - -- - l_data_key t_data_key; - l_data_description t_data_description; - l_sql VARCHAR2(500); - -- -BEGIN - -- - l_sql := 'SELECT 1, ' || CHR(39) || 'First key' || CHR(39) || - ' FROM DUAL '|| - 'UNION ALL '|| - 'SELECT 2, ' || CHR(39) || 'Second key ' || CHR(39) || - ' FROM DUAL'; - -- - EXECUTE IMMEDIATE l_sql BULK COLLECT - INTO l_data_key, l_data_description; - -- -END EXAMPLE_PROCEDURE; -"] ++- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0, @Sourcecode = "--\n-- BSD-style license; for more info see http://pmd.sourceforge.net/license.html\n--\n\nCREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS\n --\n TYPE t_data_key IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;\n TYPE t_data_description IS TABLE OF VARCHAR2(100) INDEX BY BINARY_INTEGER;\n --\n l_data_key t_data_key;\n l_data_description t_data_description;\n l_sql VARCHAR2(500);\n --\nBEGIN\n --\n l_sql := \'SELECT 1, \' || CHR(39) || \'First key\' || CHR(39) || \n \' FROM DUAL \'||\n \'UNION ALL \'||\n \'SELECT 2, \' || CHR(39) || \'Second key \' || CHR(39) || \n \' FROM DUAL\';\n --\n EXECUTE IMMEDIATE l_sql BULK COLLECT\n INTO l_data_key, l_data_description;\n --\nEND EXAMPLE_PROCEDURE;\n"] +- Global[@CanonicalImage = null] +- ProgramUnit[@CanonicalImage = null, @MethodName = "EXAMPLE_PROCEDURE", @Name = "EXAMPLE_PROCEDURE", @ObjectName = null] +- MethodDeclarator[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE", @ParameterCount = 1] @@ -71,17 +46,17 @@ END EXAMPLE_PROCEDURE; | +- NumericLiteral[@CanonicalImage = "500", @Image = "500"] +- Statement[@CanonicalImage = null] | +- UnlabelledStatement[@CanonicalImage = null] - | +- Expression[@CanonicalImage = "L_SQL := 'SELECT 1, ' || CHR || 'FIRST KEY' || CHR || ' FROM DUAL ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'SECOND KEY ' || CHR || ' FROM DUAL'", @Image = "l_sql := 'SELECT 1, ' || CHR || 'First key' || CHR || ' FROM DUAL ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'Second key ' || CHR || ' FROM DUAL'"] - | +- Assignment[@CanonicalImage = "L_SQL := 'SELECT 1, ' || CHR || 'FIRST KEY' || CHR || ' FROM DUAL ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'SECOND KEY ' || CHR || ' FROM DUAL'", @Image = "l_sql := 'SELECT 1, ' || CHR || 'First key' || CHR || ' FROM DUAL ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'Second key ' || CHR || ' FROM DUAL'"] + | +- Expression[@CanonicalImage = "L_SQL := \'SELECT 1, \' || CHR || \'FIRST KEY\' || CHR || \' FROM DUAL \' || \'UNION ALL \' || \'SELECT 2, \' || CHR || \'SECOND KEY \' || CHR || \' FROM DUAL\'", @Image = "l_sql := \'SELECT 1, \' || CHR || \'First key\' || CHR || \' FROM DUAL \' || \'UNION ALL \' || \'SELECT 2, \' || CHR || \'Second key \' || CHR || \' FROM DUAL\'"] + | +- Assignment[@CanonicalImage = "L_SQL := \'SELECT 1, \' || CHR || \'FIRST KEY\' || CHR || \' FROM DUAL \' || \'UNION ALL \' || \'SELECT 2, \' || CHR || \'SECOND KEY \' || CHR || \' FROM DUAL\'", @Image = "l_sql := \'SELECT 1, \' || CHR || \'First key\' || CHR || \' FROM DUAL \' || \'UNION ALL \' || \'SELECT 2, \' || CHR || \'Second key \' || CHR || \' FROM DUAL\'"] | +- PrimaryPrefix[@CanonicalImage = "L_SQL", @Image = "l_sql", @SelfModifier = false] | | +- SimpleExpression[@CanonicalImage = "L_SQL", @Image = "l_sql"] | | +- Column[@CanonicalImage = "L_SQL", @Image = "l_sql"] | | +- ID[@CanonicalImage = "L_SQL", @Image = "l_sql"] - | +- Expression[@CanonicalImage = "'SELECT 1, ' || CHR || 'FIRST KEY' || CHR || ' FROM DUAL ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'SECOND KEY ' || CHR || ' FROM DUAL'", @Image = "'SELECT 1, ' || CHR || 'First key' || CHR || ' FROM DUAL ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'Second key ' || CHR || ' FROM DUAL'"] - | +- AdditiveExpression[@CanonicalImage = "'SELECT 1, ' || CHR || 'FIRST KEY' || CHR || ' FROM DUAL ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'SECOND KEY ' || CHR || ' FROM DUAL'", @Image = "'SELECT 1, ' || CHR || 'First key' || CHR || ' FROM DUAL ' || 'UNION ALL ' || 'SELECT 2, ' || CHR || 'Second key ' || CHR || ' FROM DUAL'"] - | +- PrimaryPrefix[@CanonicalImage = "'SELECT 1, '", @Image = "'SELECT 1, '", @SelfModifier = false] - | | +- Literal[@CanonicalImage = "'SELECT 1, '", @Image = "'SELECT 1, '"] - | | +- StringLiteral[@CanonicalImage = "'SELECT 1, '", @Image = "'SELECT 1, '", @String = "SELECT 1, "] + | +- Expression[@CanonicalImage = "\'SELECT 1, \' || CHR || \'FIRST KEY\' || CHR || \' FROM DUAL \' || \'UNION ALL \' || \'SELECT 2, \' || CHR || \'SECOND KEY \' || CHR || \' FROM DUAL\'", @Image = "\'SELECT 1, \' || CHR || \'First key\' || CHR || \' FROM DUAL \' || \'UNION ALL \' || \'SELECT 2, \' || CHR || \'Second key \' || CHR || \' FROM DUAL\'"] + | +- AdditiveExpression[@CanonicalImage = "\'SELECT 1, \' || CHR || \'FIRST KEY\' || CHR || \' FROM DUAL \' || \'UNION ALL \' || \'SELECT 2, \' || CHR || \'SECOND KEY \' || CHR || \' FROM DUAL\'", @Image = "\'SELECT 1, \' || CHR || \'First key\' || CHR || \' FROM DUAL \' || \'UNION ALL \' || \'SELECT 2, \' || CHR || \'Second key \' || CHR || \' FROM DUAL\'"] + | +- PrimaryPrefix[@CanonicalImage = "\'SELECT 1, \'", @Image = "\'SELECT 1, \'", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "\'SELECT 1, \'", @Image = "\'SELECT 1, \'"] + | | +- StringLiteral[@CanonicalImage = "\'SELECT 1, \'", @Image = "\'SELECT 1, \'", @String = "SELECT 1, "] | +- PrimaryPrefix[@CanonicalImage = "CHR", @Image = "CHR", @SelfModifier = false] | | +- FunctionCall[@CanonicalImage = "CHR", @Image = "CHR"] | | +- FunctionName[@CanonicalImage = "CHR", @Image = "CHR"] @@ -93,9 +68,9 @@ END EXAMPLE_PROCEDURE; | | +- PrimaryPrefix[@CanonicalImage = "39", @Image = "39", @SelfModifier = false] | | +- Literal[@CanonicalImage = "39", @Image = "39"] | | +- NumericLiteral[@CanonicalImage = "39", @Image = "39"] - | +- PrimaryPrefix[@CanonicalImage = "'FIRST KEY'", @Image = "'First key'", @SelfModifier = false] - | | +- Literal[@CanonicalImage = "'FIRST KEY'", @Image = "'First key'"] - | | +- StringLiteral[@CanonicalImage = "'FIRST KEY'", @Image = "'First key'", @String = "First key"] + | +- PrimaryPrefix[@CanonicalImage = "\'FIRST KEY\'", @Image = "\'First key\'", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "\'FIRST KEY\'", @Image = "\'First key\'"] + | | +- StringLiteral[@CanonicalImage = "\'FIRST KEY\'", @Image = "\'First key\'", @String = "First key"] | +- PrimaryPrefix[@CanonicalImage = "CHR", @Image = "CHR", @SelfModifier = false] | | +- FunctionCall[@CanonicalImage = "CHR", @Image = "CHR"] | | +- FunctionName[@CanonicalImage = "CHR", @Image = "CHR"] @@ -107,15 +82,15 @@ END EXAMPLE_PROCEDURE; | | +- PrimaryPrefix[@CanonicalImage = "39", @Image = "39", @SelfModifier = false] | | +- Literal[@CanonicalImage = "39", @Image = "39"] | | +- NumericLiteral[@CanonicalImage = "39", @Image = "39"] - | +- PrimaryPrefix[@CanonicalImage = "' FROM DUAL '", @Image = "' FROM DUAL '", @SelfModifier = false] - | | +- Literal[@CanonicalImage = "' FROM DUAL '", @Image = "' FROM DUAL '"] - | | +- StringLiteral[@CanonicalImage = "' FROM DUAL '", @Image = "' FROM DUAL '", @String = " FROM DUAL "] - | +- PrimaryPrefix[@CanonicalImage = "'UNION ALL '", @Image = "'UNION ALL '", @SelfModifier = false] - | | +- Literal[@CanonicalImage = "'UNION ALL '", @Image = "'UNION ALL '"] - | | +- StringLiteral[@CanonicalImage = "'UNION ALL '", @Image = "'UNION ALL '", @String = "UNION ALL "] - | +- PrimaryPrefix[@CanonicalImage = "'SELECT 2, '", @Image = "'SELECT 2, '", @SelfModifier = false] - | | +- Literal[@CanonicalImage = "'SELECT 2, '", @Image = "'SELECT 2, '"] - | | +- StringLiteral[@CanonicalImage = "'SELECT 2, '", @Image = "'SELECT 2, '", @String = "SELECT 2, "] + | +- PrimaryPrefix[@CanonicalImage = "\' FROM DUAL \'", @Image = "\' FROM DUAL \'", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "\' FROM DUAL \'", @Image = "\' FROM DUAL \'"] + | | +- StringLiteral[@CanonicalImage = "\' FROM DUAL \'", @Image = "\' FROM DUAL \'", @String = " FROM DUAL "] + | +- PrimaryPrefix[@CanonicalImage = "\'UNION ALL \'", @Image = "\'UNION ALL \'", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "\'UNION ALL \'", @Image = "\'UNION ALL \'"] + | | +- StringLiteral[@CanonicalImage = "\'UNION ALL \'", @Image = "\'UNION ALL \'", @String = "UNION ALL "] + | +- PrimaryPrefix[@CanonicalImage = "\'SELECT 2, \'", @Image = "\'SELECT 2, \'", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "\'SELECT 2, \'", @Image = "\'SELECT 2, \'"] + | | +- StringLiteral[@CanonicalImage = "\'SELECT 2, \'", @Image = "\'SELECT 2, \'", @String = "SELECT 2, "] | +- PrimaryPrefix[@CanonicalImage = "CHR", @Image = "CHR", @SelfModifier = false] | | +- FunctionCall[@CanonicalImage = "CHR", @Image = "CHR"] | | +- FunctionName[@CanonicalImage = "CHR", @Image = "CHR"] @@ -127,9 +102,9 @@ END EXAMPLE_PROCEDURE; | | +- PrimaryPrefix[@CanonicalImage = "39", @Image = "39", @SelfModifier = false] | | +- Literal[@CanonicalImage = "39", @Image = "39"] | | +- NumericLiteral[@CanonicalImage = "39", @Image = "39"] - | +- PrimaryPrefix[@CanonicalImage = "'SECOND KEY '", @Image = "'Second key '", @SelfModifier = false] - | | +- Literal[@CanonicalImage = "'SECOND KEY '", @Image = "'Second key '"] - | | +- StringLiteral[@CanonicalImage = "'SECOND KEY '", @Image = "'Second key '", @String = "Second key "] + | +- PrimaryPrefix[@CanonicalImage = "\'SECOND KEY \'", @Image = "\'Second key \'", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "\'SECOND KEY \'", @Image = "\'Second key \'"] + | | +- StringLiteral[@CanonicalImage = "\'SECOND KEY \'", @Image = "\'Second key \'", @String = "Second key "] | +- PrimaryPrefix[@CanonicalImage = "CHR", @Image = "CHR", @SelfModifier = false] | | +- FunctionCall[@CanonicalImage = "CHR", @Image = "CHR"] | | +- FunctionName[@CanonicalImage = "CHR", @Image = "CHR"] @@ -141,9 +116,9 @@ END EXAMPLE_PROCEDURE; | | +- PrimaryPrefix[@CanonicalImage = "39", @Image = "39", @SelfModifier = false] | | +- Literal[@CanonicalImage = "39", @Image = "39"] | | +- NumericLiteral[@CanonicalImage = "39", @Image = "39"] - | +- PrimaryPrefix[@CanonicalImage = "' FROM DUAL'", @Image = "' FROM DUAL'", @SelfModifier = false] - | +- Literal[@CanonicalImage = "' FROM DUAL'", @Image = "' FROM DUAL'"] - | +- StringLiteral[@CanonicalImage = "' FROM DUAL'", @Image = "' FROM DUAL'", @String = " FROM DUAL"] + | +- PrimaryPrefix[@CanonicalImage = "\' FROM DUAL\'", @Image = "\' FROM DUAL\'", @SelfModifier = false] + | +- Literal[@CanonicalImage = "\' FROM DUAL\'", @Image = "\' FROM DUAL\'"] + | +- StringLiteral[@CanonicalImage = "\' FROM DUAL\'", @Image = "\' FROM DUAL\'", @String = " FROM DUAL"] +- Statement[@CanonicalImage = null] | +- UnlabelledStatement[@CanonicalImage = null] | +- EmbeddedSqlStatement[@CanonicalImage = null] diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/OpenForStatement.txt b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/OpenForStatement.txt index 9697ba6fb1..65078e5959 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/OpenForStatement.txt +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/OpenForStatement.txt @@ -1,66 +1,4 @@ -+- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0, @Sourcecode = "-- --- See https://docs.oracle.com/en/database/oracle/oracle-database/18/lnpls/OPEN-FOR-statement.html#GUID-EB7AF439-FDD3-4461-9E3F-B621E8ABFB96 --- https://github.com/pmd/pmd/issues/3487 --- - -CREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS - -- - TYPE t_ref_cursor IS REF CURSOR; - -- - l_ref_cursor t_ref_cursor; - -- -BEGIN - -- - OPEN l_ref_cursor FOR - SELECT * - FROM DUAL; - -- -END EXAMPLE_PROCEDURE; - --- --- Example 6-26 Fetching Data with Cursor Variables --- https://docs.oracle.com/en/database/oracle/oracle-database/18/lnpls/static-sql.html#GUID-AA5A2016-1B76-4961-9AFB-EB052F0D0FB2 --- -DECLARE - cv SYS_REFCURSOR; -- cursor variable - - v_lastname employees.last_name%TYPE; -- variable for last_name - v_jobid employees.job_id%TYPE; -- variable for job_id - - query_2 VARCHAR2(200) := - 'SELECT * FROM employees - WHERE REGEXP_LIKE (job_id, ''[ACADFIMKSA]_M[ANGR]'') - ORDER BY job_id'; - - v_employees employees%ROWTYPE; -- record variable row of table - -BEGIN - OPEN cv FOR - SELECT last_name, job_id FROM employees - WHERE REGEXP_LIKE (job_id, 'S[HT]_CLERK') - ORDER BY last_name; - - LOOP -- Fetches 2 columns into variables - FETCH cv INTO v_lastname, v_jobid; - EXIT WHEN cv%NOTFOUND; - DBMS_OUTPUT.PUT_LINE( RPAD(v_lastname, 25, ' ') || v_jobid ); - END LOOP; - - DBMS_OUTPUT.PUT_LINE( '-------------------------------------' ); - - OPEN cv FOR query_2; - - LOOP -- Fetches entire row into the v_employees record - FETCH cv INTO v_employees; - EXIT WHEN cv%NOTFOUND; - DBMS_OUTPUT.PUT_LINE( RPAD(v_employees.last_name, 25, ' ') || - v_employees.job_id ); - END LOOP; - - CLOSE cv; -END; -/ -"] ++- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0, @Sourcecode = "--\n-- See https://docs.oracle.com/en/database/oracle/oracle-database/18/lnpls/OPEN-FOR-statement.html#GUID-EB7AF439-FDD3-4461-9E3F-B621E8ABFB96\n-- https://github.com/pmd/pmd/issues/3487\n--\n\nCREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS\n --\n TYPE t_ref_cursor IS REF CURSOR;\n --\n l_ref_cursor t_ref_cursor;\n --\nBEGIN\n --\n OPEN l_ref_cursor FOR\n SELECT *\n FROM DUAL;\n --\nEND EXAMPLE_PROCEDURE;\n\n--\n-- Example 6-26 Fetching Data with Cursor Variables\n-- https://docs.oracle.com/en/database/oracle/oracle-database/18/lnpls/static-sql.html#GUID-AA5A2016-1B76-4961-9AFB-EB052F0D0FB2\n--\nDECLARE\n cv SYS_REFCURSOR; -- cursor variable\n \n v_lastname employees.last_name%TYPE; -- variable for last_name\n v_jobid employees.job_id%TYPE; -- variable for job_id\n \n query_2 VARCHAR2(200) :=\n \'SELECT * FROM employees\n WHERE REGEXP_LIKE (job_id, \'\'[ACADFIMKSA]_M[ANGR]\'\')\n ORDER BY job_id\';\n \n v_employees employees%ROWTYPE; -- record variable row of table\n \nBEGIN\n OPEN cv FOR\n SELECT last_name, job_id FROM employees\n WHERE REGEXP_LIKE (job_id, \'S[HT]_CLERK\')\n ORDER BY last_name;\n \n LOOP -- Fetches 2 columns into variables\n FETCH cv INTO v_lastname, v_jobid;\n EXIT WHEN cv%NOTFOUND;\n DBMS_OUTPUT.PUT_LINE( RPAD(v_lastname, 25, \' \') || v_jobid );\n END LOOP;\n \n DBMS_OUTPUT.PUT_LINE( \'-------------------------------------\' );\n \n OPEN cv FOR query_2;\n \n LOOP -- Fetches entire row into the v_employees record\n FETCH cv INTO v_employees;\n EXIT WHEN cv%NOTFOUND;\n DBMS_OUTPUT.PUT_LINE( RPAD(v_employees.last_name, 25, \' \') ||\n v_employees.job_id );\n END LOOP;\n \n CLOSE cv;\nEND;\n/\n"] +- Global[@CanonicalImage = null] | +- ProgramUnit[@CanonicalImage = null, @MethodName = "EXAMPLE_PROCEDURE", @Name = "EXAMPLE_PROCEDURE", @ObjectName = null] | +- MethodDeclarator[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE", @ParameterCount = 1] @@ -123,43 +61,17 @@ END; | | +- QualifiedID[@CanonicalImage = "JOB_ID", @Image = "job_id"] | +- DeclarativeUnit[@CanonicalImage = null] | | +- VariableOrConstantDeclaration[@CanonicalImage = null] - | | +- VariableOrConstantDeclarator[@CanonicalImage = "QUERY_2 VARCHAR2(200) := 'SELECT * FROM EMPLOYEES - WHERE REGEXP_LIKE (JOB_ID, ''[ACADFIMKSA]_M[ANGR]'') - ORDER BY JOB_ID'", @Image = "query_2 VARCHAR2(200) := 'SELECT * FROM employees - WHERE REGEXP_LIKE (job_id, ''[ACADFIMKSA]_M[ANGR]'') - ORDER BY job_id'"] + | | +- VariableOrConstantDeclarator[@CanonicalImage = "QUERY_2 VARCHAR2(200) := \'SELECT * FROM EMPLOYEES\n WHERE REGEXP_LIKE (JOB_ID, \'\'[ACADFIMKSA]_M[ANGR]\'\')\n ORDER BY JOB_ID\'", @Image = "query_2 VARCHAR2(200) := \'SELECT * FROM employees\n WHERE REGEXP_LIKE (job_id, \'\'[ACADFIMKSA]_M[ANGR]\'\')\n ORDER BY job_id\'"] | | +- VariableOrConstantDeclaratorId[@Array = false, @ArrayDepth = 0, @CanonicalImage = "QUERY_2", @Image = "query_2"] | | | +- ID[@CanonicalImage = "QUERY_2", @Image = "query_2"] | | +- Datatype[@CanonicalImage = "VARCHAR2(200)", @Image = "VARCHAR2(200)", @TypeImage = "VARCHAR2(200)"] | | | +- ScalarDataTypeName[@CanonicalImage = "VARCHAR2(200)", @Image = "VARCHAR2(200)"] | | | +- NumericLiteral[@CanonicalImage = "200", @Image = "200"] - | | +- VariableOrConstantInitializer[@CanonicalImage = "'SELECT * FROM EMPLOYEES - WHERE REGEXP_LIKE (JOB_ID, ''[ACADFIMKSA]_M[ANGR]'') - ORDER BY JOB_ID'", @Image = "'SELECT * FROM employees - WHERE REGEXP_LIKE (job_id, ''[ACADFIMKSA]_M[ANGR]'') - ORDER BY job_id'"] - | | +- Expression[@CanonicalImage = "'SELECT * FROM EMPLOYEES - WHERE REGEXP_LIKE (JOB_ID, ''[ACADFIMKSA]_M[ANGR]'') - ORDER BY JOB_ID'", @Image = "'SELECT * FROM employees - WHERE REGEXP_LIKE (job_id, ''[ACADFIMKSA]_M[ANGR]'') - ORDER BY job_id'"] - | | +- PrimaryPrefix[@CanonicalImage = "'SELECT * FROM EMPLOYEES - WHERE REGEXP_LIKE (JOB_ID, ''[ACADFIMKSA]_M[ANGR]'') - ORDER BY JOB_ID'", @Image = "'SELECT * FROM employees - WHERE REGEXP_LIKE (job_id, ''[ACADFIMKSA]_M[ANGR]'') - ORDER BY job_id'", @SelfModifier = false] - | | +- Literal[@CanonicalImage = "'SELECT * FROM EMPLOYEES - WHERE REGEXP_LIKE (JOB_ID, ''[ACADFIMKSA]_M[ANGR]'') - ORDER BY JOB_ID'", @Image = "'SELECT * FROM employees - WHERE REGEXP_LIKE (job_id, ''[ACADFIMKSA]_M[ANGR]'') - ORDER BY job_id'"] - | | +- StringLiteral[@CanonicalImage = "'SELECT * FROM EMPLOYEES - WHERE REGEXP_LIKE (JOB_ID, ''[ACADFIMKSA]_M[ANGR]'') - ORDER BY JOB_ID'", @Image = "'SELECT * FROM employees - WHERE REGEXP_LIKE (job_id, ''[ACADFIMKSA]_M[ANGR]'') - ORDER BY job_id'", @String = "SELECT * FROM employees - WHERE REGEXP_LIKE (job_id, ''[ACADFIMKSA]_M[ANGR]'') - ORDER BY job_id"] + | | +- VariableOrConstantInitializer[@CanonicalImage = "\'SELECT * FROM EMPLOYEES\n WHERE REGEXP_LIKE (JOB_ID, \'\'[ACADFIMKSA]_M[ANGR]\'\')\n ORDER BY JOB_ID\'", @Image = "\'SELECT * FROM employees\n WHERE REGEXP_LIKE (job_id, \'\'[ACADFIMKSA]_M[ANGR]\'\')\n ORDER BY job_id\'"] + | | +- Expression[@CanonicalImage = "\'SELECT * FROM EMPLOYEES\n WHERE REGEXP_LIKE (JOB_ID, \'\'[ACADFIMKSA]_M[ANGR]\'\')\n ORDER BY JOB_ID\'", @Image = "\'SELECT * FROM employees\n WHERE REGEXP_LIKE (job_id, \'\'[ACADFIMKSA]_M[ANGR]\'\')\n ORDER BY job_id\'"] + | | +- PrimaryPrefix[@CanonicalImage = "\'SELECT * FROM EMPLOYEES\n WHERE REGEXP_LIKE (JOB_ID, \'\'[ACADFIMKSA]_M[ANGR]\'\')\n ORDER BY JOB_ID\'", @Image = "\'SELECT * FROM employees\n WHERE REGEXP_LIKE (job_id, \'\'[ACADFIMKSA]_M[ANGR]\'\')\n ORDER BY job_id\'", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "\'SELECT * FROM EMPLOYEES\n WHERE REGEXP_LIKE (JOB_ID, \'\'[ACADFIMKSA]_M[ANGR]\'\')\n ORDER BY JOB_ID\'", @Image = "\'SELECT * FROM employees\n WHERE REGEXP_LIKE (job_id, \'\'[ACADFIMKSA]_M[ANGR]\'\')\n ORDER BY job_id\'"] + | | +- StringLiteral[@CanonicalImage = "\'SELECT * FROM EMPLOYEES\n WHERE REGEXP_LIKE (JOB_ID, \'\'[ACADFIMKSA]_M[ANGR]\'\')\n ORDER BY JOB_ID\'", @Image = "\'SELECT * FROM employees\n WHERE REGEXP_LIKE (job_id, \'\'[ACADFIMKSA]_M[ANGR]\'\')\n ORDER BY job_id\'", @String = "SELECT * FROM employees\n WHERE REGEXP_LIKE (job_id, \'\'[ACADFIMKSA]_M[ANGR]\'\')\n ORDER BY job_id"] | +- DeclarativeUnit[@CanonicalImage = null] | +- VariableOrConstantDeclaration[@CanonicalImage = null] | +- VariableOrConstantDeclarator[@CanonicalImage = "V_EMPLOYEES EMPLOYEES%ROWTYPE", @Image = "v_employees employees%ROWTYPE"] @@ -201,10 +113,10 @@ END; | | | +- SimpleExpression[@CanonicalImage = "JOB_ID", @Image = "job_id"] | | | +- Column[@CanonicalImage = "JOB_ID", @Image = "job_id"] | | | +- ID[@CanonicalImage = "JOB_ID", @Image = "job_id"] - | | +- SqlExpression[@CanonicalImage = "'S[HT]_CLERK'", @Image = "'S[HT]_CLERK'"] - | | +- PrimaryPrefix[@CanonicalImage = "'S[HT]_CLERK'", @Image = "'S[HT]_CLERK'", @SelfModifier = false] - | | +- Literal[@CanonicalImage = "'S[HT]_CLERK'", @Image = "'S[HT]_CLERK'"] - | | +- StringLiteral[@CanonicalImage = "'S[HT]_CLERK'", @Image = "'S[HT]_CLERK'", @String = "S[HT]_CLERK"] + | | +- SqlExpression[@CanonicalImage = "\'S[HT]_CLERK\'", @Image = "\'S[HT]_CLERK\'"] + | | +- PrimaryPrefix[@CanonicalImage = "\'S[HT]_CLERK\'", @Image = "\'S[HT]_CLERK\'", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "\'S[HT]_CLERK\'", @Image = "\'S[HT]_CLERK\'"] + | | +- StringLiteral[@CanonicalImage = "\'S[HT]_CLERK\'", @Image = "\'S[HT]_CLERK\'", @String = "S[HT]_CLERK"] | +- OrderByClause[@CanonicalImage = null] | +- SqlExpression[@CanonicalImage = "LAST_NAME", @Image = "last_name"] | +- PrimaryPrefix[@CanonicalImage = "LAST_NAME", @Image = "last_name", @SelfModifier = false] @@ -268,9 +180,9 @@ END; | | | +- Literal[@CanonicalImage = "25", @Image = "25"] | | | +- NumericLiteral[@CanonicalImage = "25", @Image = "25"] | | +- Argument[@CanonicalImage = null] - | | +- Expression[@CanonicalImage = "' '", @Image = "' '"] - | | +- PrimaryPrefix[@CanonicalImage = "' '", @Image = "' '", @SelfModifier = false] - | | +- Literal[@CanonicalImage = "' '", @Image = "' '"] + | | +- Expression[@CanonicalImage = "\' \'", @Image = "\' \'"] + | | +- PrimaryPrefix[@CanonicalImage = "\' \'", @Image = "\' \'", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "\' \'", @Image = "\' \'"] | +- PrimaryPrefix[@CanonicalImage = "V_JOBID", @Image = "v_jobid", @SelfModifier = false] | +- SimpleExpression[@CanonicalImage = "V_JOBID", @Image = "v_jobid"] | +- Column[@CanonicalImage = "V_JOBID", @Image = "v_jobid"] @@ -286,10 +198,10 @@ END; | +- Arguments[@ArgumentCount = 1, @CanonicalImage = null] | +- ArgumentList[@CanonicalImage = null] | +- Argument[@CanonicalImage = null] - | +- Expression[@CanonicalImage = "'-------------------------------------'", @Image = "'-------------------------------------'"] - | +- PrimaryPrefix[@CanonicalImage = "'-------------------------------------'", @Image = "'-------------------------------------'", @SelfModifier = false] - | +- Literal[@CanonicalImage = "'-------------------------------------'", @Image = "'-------------------------------------'"] - | +- StringLiteral[@CanonicalImage = "'-------------------------------------'", @Image = "'-------------------------------------'", @String = "-------------------------------------"] + | +- Expression[@CanonicalImage = "\'-------------------------------------\'", @Image = "\'-------------------------------------\'"] + | +- PrimaryPrefix[@CanonicalImage = "\'-------------------------------------\'", @Image = "\'-------------------------------------\'", @SelfModifier = false] + | +- Literal[@CanonicalImage = "\'-------------------------------------\'", @Image = "\'-------------------------------------\'"] + | +- StringLiteral[@CanonicalImage = "\'-------------------------------------\'", @Image = "\'-------------------------------------\'", @String = "-------------------------------------"] +- Statement[@CanonicalImage = null] | +- UnlabelledStatement[@CanonicalImage = null] | +- OpenStatement[@CanonicalImage = null] @@ -357,9 +269,9 @@ END; | | | +- Literal[@CanonicalImage = "25", @Image = "25"] | | | +- NumericLiteral[@CanonicalImage = "25", @Image = "25"] | | +- Argument[@CanonicalImage = null] - | | +- Expression[@CanonicalImage = "' '", @Image = "' '"] - | | +- PrimaryPrefix[@CanonicalImage = "' '", @Image = "' '", @SelfModifier = false] - | | +- Literal[@CanonicalImage = "' '", @Image = "' '"] + | | +- Expression[@CanonicalImage = "\' \'", @Image = "\' \'"] + | | +- PrimaryPrefix[@CanonicalImage = "\' \'", @Image = "\' \'", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "\' \'", @Image = "\' \'"] | +- PrimaryPrefix[@CanonicalImage = "V_EMPLOYEES.JOB_ID", @Image = "v_employees.job_id", @SelfModifier = false] | +- SimpleExpression[@CanonicalImage = "V_EMPLOYEES.JOB_ID", @Image = "v_employees.job_id"] | +- TableName[@CanonicalImage = "V_EMPLOYEES", @Image = "v_employees"] diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup0.txt b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup0.txt index aaa2464d78..98181dbc20 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup0.txt +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup0.txt @@ -1,29 +1,4 @@ -+- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0, @Sourcecode = "-- --- BSD-style license; for more info see http://pmd.sourceforge.net/license.html --- - -CREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS - -- - CURSOR c_example IS - SELECT a.owner, u.object_name, p.aggregate - FROM (USER_OBJECTS u) INNER JOIN (ALL_OBJECTS a) ON - u.object_name = a.object_name AND u.object_type = a.object_type AND u.object_id = a.object_id - INNER JOIN (ALL_PROCEDURES p) ON - p.owner = a.owner AND p.object_name = a.object_name AND p.object_type = a.object_type - WHERE a.owner = USER; - -- -BEGIN - -- - FOR l_object IN c_example LOOP - -- - DBMS_OUTPUT.Put_Line(l_object.owner); - DBMS_OUTPUT.Put_Line(l_object.object_name); - DBMS_OUTPUT.Put_Line(l_object.aggregate); - -- - END LOOP; - -- -END EXAMPLE_PROCEDURE; -"] ++- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0, @Sourcecode = "--\n-- BSD-style license; for more info see http://pmd.sourceforge.net/license.html\n--\n\nCREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS\n --\n CURSOR c_example IS\n SELECT a.owner, u.object_name, p.aggregate\n FROM (USER_OBJECTS u) INNER JOIN (ALL_OBJECTS a) ON\n u.object_name = a.object_name AND u.object_type = a.object_type AND u.object_id = a.object_id\n INNER JOIN (ALL_PROCEDURES p) ON\n p.owner = a.owner AND p.object_name = a.object_name AND p.object_type = a.object_type\n WHERE a.owner = USER;\n --\nBEGIN\n --\n FOR l_object IN c_example LOOP\n --\n DBMS_OUTPUT.Put_Line(l_object.owner);\n DBMS_OUTPUT.Put_Line(l_object.object_name);\n DBMS_OUTPUT.Put_Line(l_object.aggregate);\n --\n END LOOP;\n --\nEND EXAMPLE_PROCEDURE;\n"] +- Global[@CanonicalImage = null] +- ProgramUnit[@CanonicalImage = null, @MethodName = "EXAMPLE_PROCEDURE", @Name = "EXAMPLE_PROCEDURE", @ObjectName = null] +- MethodDeclarator[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE", @ParameterCount = 1] diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup1.txt b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup1.txt index 8bc9983c66..25349ff15d 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup1.txt +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup1.txt @@ -1,29 +1,4 @@ -+- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0, @Sourcecode = "-- --- BSD-style license; for more info see http://pmd.sourceforge.net/license.html --- - -CREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS - -- - CURSOR c_example IS - SELECT a.owner, u.object_name, p.aggregate - FROM (((USER_OBJECTS u) INNER JOIN (ALL_OBJECTS a) ON - u.object_name = a.object_name AND u.object_type = a.object_type AND u.object_id = a.object_id) - INNER JOIN (ALL_PROCEDURES p) ON - p.owner = a.owner AND p.object_name = a.object_name AND p.object_type = a.object_type) - WHERE a.owner = USER; - -- -BEGIN - -- - FOR l_object IN c_example LOOP - -- - DBMS_OUTPUT.Put_Line(l_object.owner); - DBMS_OUTPUT.Put_Line(l_object.object_name); - DBMS_OUTPUT.Put_Line(l_object.aggregate); - -- - END LOOP; - -- -END EXAMPLE_PROCEDURE; -"] ++- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0, @Sourcecode = "--\n-- BSD-style license; for more info see http://pmd.sourceforge.net/license.html\n--\n\nCREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS\n --\n CURSOR c_example IS\n SELECT a.owner, u.object_name, p.aggregate\n FROM (((USER_OBJECTS u) INNER JOIN (ALL_OBJECTS a) ON\n u.object_name = a.object_name AND u.object_type = a.object_type AND u.object_id = a.object_id)\n INNER JOIN (ALL_PROCEDURES p) ON\n p.owner = a.owner AND p.object_name = a.object_name AND p.object_type = a.object_type)\n WHERE a.owner = USER;\n --\nBEGIN\n --\n FOR l_object IN c_example LOOP\n --\n DBMS_OUTPUT.Put_Line(l_object.owner);\n DBMS_OUTPUT.Put_Line(l_object.object_name);\n DBMS_OUTPUT.Put_Line(l_object.aggregate);\n --\n END LOOP;\n --\nEND EXAMPLE_PROCEDURE;\n"] +- Global[@CanonicalImage = null] +- ProgramUnit[@CanonicalImage = null, @MethodName = "EXAMPLE_PROCEDURE", @Name = "EXAMPLE_PROCEDURE", @ObjectName = null] +- MethodDeclarator[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE", @ParameterCount = 1] diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup2.txt b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup2.txt index ba0d002fba..a0a5106dc1 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup2.txt +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup2.txt @@ -1,23 +1,4 @@ -+- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0, @Sourcecode = "-- --- BSD-style license; for more info see http://pmd.sourceforge.net/license.html --- - -CREATE OR REPLACE PROCEDURE TEST_PROCEDURE IS - -- - CURSOR c_test IS - SELECT si.sid, sn.name, sa.age, ss.score, sp.parent - FROM ((((STUDENT_INFO si) INNER JOIN (STUDENT_AGE sa) on si.sid = sa.sid) - INNER JOIN - (STUDENT_SCORE ss) on si.sid = sp.sid) - INNER JOIN - (STUDENT_PARENT sp) on si.sid = sp.sid) - WHERE si.sid = '114514'; - -- -BEGIN - -- - -- -END EXAMPLE_PROCEDURE; -"] ++- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0, @Sourcecode = "--\n-- BSD-style license; for more info see http://pmd.sourceforge.net/license.html\n--\n\nCREATE OR REPLACE PROCEDURE TEST_PROCEDURE IS\n --\n CURSOR c_test IS\n SELECT si.sid, sn.name, sa.age, ss.score, sp.parent\n FROM ((((STUDENT_INFO si) INNER JOIN (STUDENT_AGE sa) on si.sid = sa.sid)\n INNER JOIN\n (STUDENT_SCORE ss) on si.sid = sp.sid)\n INNER JOIN\n (STUDENT_PARENT sp) on si.sid = sp.sid)\n WHERE si.sid = \'114514\';\n --\nBEGIN\n --\n --\nEND EXAMPLE_PROCEDURE;\n"] +- Global[@CanonicalImage = null] +- ProgramUnit[@CanonicalImage = null, @MethodName = "TEST_PROCEDURE", @Name = "TEST_PROCEDURE", @ObjectName = null] +- MethodDeclarator[@CanonicalImage = "TEST_PROCEDURE", @Image = "TEST_PROCEDURE", @ParameterCount = 1] @@ -147,8 +128,8 @@ END EXAMPLE_PROCEDURE; | | | +- ID[@CanonicalImage = "SI", @Image = "si"] | | +- Column[@CanonicalImage = "SID", @Image = "sid"] | | +- ID[@CanonicalImage = "SID", @Image = "sid"] - | +- SqlExpression[@CanonicalImage = "'114514'", @Image = "'114514'"] - | +- PrimaryPrefix[@CanonicalImage = "'114514'", @Image = "'114514'", @SelfModifier = false] - | +- Literal[@CanonicalImage = "'114514'", @Image = "'114514'"] - | +- StringLiteral[@CanonicalImage = "'114514'", @Image = "'114514'", @String = "114514"] + | +- SqlExpression[@CanonicalImage = "\'114514\'", @Image = "\'114514\'"] + | +- PrimaryPrefix[@CanonicalImage = "\'114514\'", @Image = "\'114514\'", @SelfModifier = false] + | +- Literal[@CanonicalImage = "\'114514\'", @Image = "\'114514\'"] + | +- StringLiteral[@CanonicalImage = "\'114514\'", @Image = "\'114514\'", @String = "114514"] +- ID[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE"] diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParsingExclusion.txt b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParsingExclusion.txt index a0f21db435..1fea26da47 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParsingExclusion.txt +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParsingExclusion.txt @@ -1,19 +1,4 @@ -+- Input[@CanonicalImage = null, @ExcludedLinesCount = 6, @ExcludedRangesCount = 2, @Sourcecode = "begin - do_something(); - -- pmd-exclude-begin: PMD does not like dbms_lob.trim (clash with TrimExpression) - dbms_lob.trim(the_blob, 1000); - -- pmd-exclude-end - do_something_else(x); -end; -/ - -select dummy from dual a -where 1=1 - -- pmd-exclude-begin: PMD does not like scalar subqueries in WHERE conditions - and 'J' = (select max('J') from dual b) - -- pmd-exclude-end -; -"] ++- Input[@CanonicalImage = null, @ExcludedLinesCount = 6, @ExcludedRangesCount = 2, @Sourcecode = "begin\n do_something();\n -- pmd-exclude-begin: PMD does not like dbms_lob.trim (clash with TrimExpression)\n dbms_lob.trim(the_blob, 1000);\n -- pmd-exclude-end\n do_something_else(x);\nend;\n/\n\nselect dummy from dual a\nwhere 1=1\n -- pmd-exclude-begin: PMD does not like scalar subqueries in WHERE conditions\n and \'J\' = (select max(\'J\') from dual b)\n -- pmd-exclude-end\n;\n"] +- Global[@CanonicalImage = null] | +- Block[@CanonicalImage = null] | +- Statement[@CanonicalImage = null] diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/SelectIntoArray.txt b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/SelectIntoArray.txt index 2709539e5e..0c6b7feed7 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/SelectIntoArray.txt +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/SelectIntoArray.txt @@ -1,26 +1,4 @@ -+- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0, @Sourcecode = "-- --- See https://github.com/pmd/pmd/issues/3515 --- - -CREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS - -- - TYPE example_data_rt IS RECORD( - field_one PLS_INTEGER, - field_two PLS_INTEGER, - field_three PLS_INTEGER); - -- - TYPE example_data_aat IS TABLE OF example_data_rt INDEX BY BINARY_INTEGER; - -- - l_example_data example_data_aat; - -- -BEGIN - -- - SELECT 1 field_value_one, 2 field_value_two, 3 field_value_three - INTO l_example_data(1).field_one,l_example_data(1).field_two,l_example_data(1).field_three - FROM DUAL; - -- -END EXAMPLE_PROCEDURE; -"] ++- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0, @Sourcecode = "--\n-- See https://github.com/pmd/pmd/issues/3515\n--\n\nCREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS\n --\n TYPE example_data_rt IS RECORD(\n field_one PLS_INTEGER,\n field_two PLS_INTEGER,\n field_three PLS_INTEGER);\n --\n TYPE example_data_aat IS TABLE OF example_data_rt INDEX BY BINARY_INTEGER;\n --\n l_example_data example_data_aat;\n --\nBEGIN\n --\n SELECT 1 field_value_one, 2 field_value_two, 3 field_value_three\n INTO l_example_data(1).field_one,l_example_data(1).field_two,l_example_data(1).field_three\n FROM DUAL;\n --\nEND EXAMPLE_PROCEDURE;\n"] +- Global[@CanonicalImage = null] +- ProgramUnit[@CanonicalImage = null, @MethodName = "EXAMPLE_PROCEDURE", @Name = "EXAMPLE_PROCEDURE", @ObjectName = null] +- MethodDeclarator[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE", @ParameterCount = 1] diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/SqlPlusLexicalVariablesIssue195.txt b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/SqlPlusLexicalVariablesIssue195.txt index d5ddc15d5a..2771c23abf 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/SqlPlusLexicalVariablesIssue195.txt +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/SqlPlusLexicalVariablesIssue195.txt @@ -1,9 +1,3 @@ -+- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0, @Sourcecode = " --- see https://github.com/pmd/pmd/issues/195 --- both define and spool are SQL*Plus commands, and they should not be ended with a semi-colon. - -define patch_name = acme_module -spool &patch_name..log -"] ++- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0, @Sourcecode = "\n-- see https://github.com/pmd/pmd/issues/195\n-- both define and spool are SQL*Plus commands, and they should not be ended with a semi-colon.\n\ndefine patch_name = acme_module\nspool &patch_name..log\n"] +- SqlPlusCommand[@CanonicalImage = "DEFINE PATCH_NAME = ACME_MODULE", @Image = "define patch_name = acme_module "] +- SqlPlusCommand[@CanonicalImage = "SPOOL &PATCH_NAME. . LOG", @Image = "spool &patch_name. . log "] From 94057f688d041ad140604bb1fb1249bad54adb31 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 29 Apr 2022 11:56:36 +0200 Subject: [PATCH 156/180] [doc] Update release notes (#3943) --- 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 7435aeab16..c3bcdfd719 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -103,6 +103,7 @@ missing features or bugs as new [issues](https://github.com/pmd/pmd/issues). * [#3928](https://github.com/pmd/pmd/pull/3928): \[plsql] Fix plsql parsing error in parenthesis groups - [@LiGaOg](https://github.com/LiGaOg) * [#3935](https://github.com/pmd/pmd/pull/3935): \[plsql] Fix parser exception in EXECUTE IMMEDIATE BULK COLLECT #3687 - [@Scrsloota](https://github.com/Scrsloota) * [#3938](https://github.com/pmd/pmd/pull/3938): \[java] Modify SimplifiedTernary to meet the missing case #3603 - [@VoidxHoshi](https://github.com/VoidxHoshi) +* [#3943](https://github.com/pmd/pmd/pull/3943): chore: Set permissions for GitHub actions - [@naveensrinivasan](https://github.com/naveensrinivasan) {% endtocmaker %} From 47beb1c3cdcb8af1a0334c1c16bf589e760a3077 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 29 Apr 2022 11:57:00 +0200 Subject: [PATCH 157/180] Add @naveensrinivasan as a contributor --- .all-contributorsrc | 9 +++ docs/pages/pmd/projectdocs/credits.md | 101 +++++++++++++------------- 2 files changed, 60 insertions(+), 50 deletions(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 66cd053fa8..dcac68bf60 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -6630,6 +6630,15 @@ "contributions": [ "code" ] + }, + { + "login": "naveensrinivasan", + "name": "Naveen", + "avatar_url": "https://avatars.githubusercontent.com/u/172697?v=4", + "profile": "https://naveensrinivasan.dev/", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 7, diff --git a/docs/pages/pmd/projectdocs/credits.md b/docs/pages/pmd/projectdocs/credits.md index b252c1d257..3f6b6213cf 100644 --- a/docs/pages/pmd/projectdocs/credits.md +++ b/docs/pages/pmd/projectdocs/credits.md @@ -496,451 +496,452 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
    Nathan Reynolds

    🐛
    Nathan Reynolds

    🐛
    Nathanaël

    🐛 +
    Naveen

    💻
    Nazdravi

    🐛 -
    Neha-Dhonde

    🐛 +
    Neha-Dhonde

    🐛
    Nicholas Doyle

    🐛
    Nick Butcher

    🐛
    Nico Gallinal

    🐛
    Nicola Dal Maso

    🐛
    Nicolas Filotto

    💻
    Nikita Chursin

    🐛 -
    Niklas Baudy

    🐛 +
    Niklas Baudy

    🐛
    Nikolas Havrikov

    🐛
    Nilesh Virkar

    🐛
    Nimit Patel

    🐛
    Niranjan Harpale

    🐛
    Noah Sussman

    🐛
    Noah0120

    🐛 -
    Noam Tamim

    🐛 +
    Noam Tamim

    🐛
    Noel Grandin

    🐛
    Olaf Haalstra

    🐛
    Oleg Pavlenko

    🐛
    Oleksii Dykov

    💻
    Oliver Eikemeier

    🐛
    Olivier Parent

    💻 🐛 -
    Ollie Abbey

    💻 🐛 +
    Ollie Abbey

    💻 🐛
    OverDrone

    🐛
    Ozan Gulle

    💻 🐛
    PUNEET JAIN

    🐛
    Parbati Bose

    🐛
    Paul Berg

    🐛
    Pavel Bludov

    🐛 -
    Pavel Mička

    🐛 +
    Pavel Mička

    🐛
    Pedro Nuno Santos

    🐛
    Pedro Rijo

    🐛
    Pelisse Romain

    💻 📖 🐛
    Pete Davids

    🐛
    Peter Bruin

    🐛
    Peter Chittum

    💻 🐛 -
    Peter Cudmore

    🐛 +
    Peter Cudmore

    🐛
    Peter Kasson

    🐛
    Peter Kofler

    🐛
    Pham Hai Trung

    🐛
    Philip Graf

    💻 🐛
    Philip Hachey

    🐛
    Philippe Ozil

    🐛 -
    Phinehas Artemix

    🐛 +
    Phinehas Artemix

    🐛
    Phokham Nonava

    🐛
    Piotr Szymański

    🐛
    Piotrek Żygieło

    💻 🐛
    Pranay Jaiswal

    🐛
    Prasad Kamath

    🐛
    Prasanna

    🐛 -
    Presh-AR

    🐛 +
    Presh-AR

    🐛
    Puneet1726

    🐛
    Rafael Cortês

    🐛
    RaheemShaik999

    🐛
    RajeshR

    💻 🐛
    Ramachandra Mohan

    🐛
    Raquel Pau

    🐛 -
    Ravikiran Janardhana

    🐛 +
    Ravikiran Janardhana

    🐛
    Reda Benhemmouche

    🐛
    Renato Oliveira

    💻 🐛
    Rich DiCroce

    🐛
    Riot R1cket

    🐛
    Rishabh Jain

    🐛
    RishabhDeep Singh

    🐛 -
    Robbie Martinus

    💻 🐛 +
    Robbie Martinus

    💻 🐛
    Robert Henry

    🐛
    Robert Painsi

    🐛
    Robert Russell

    🐛
    Robert Sösemann

    💻 📖 📢 🐛
    Robert Whitebit

    🐛
    Robin Richtsfeld

    🐛 -
    Robin Stocker

    💻 🐛 +
    Robin Stocker

    💻 🐛
    Robin Wils

    🐛
    RochusOest

    🐛
    Rodolfo Noviski

    🐛
    Rodrigo Casara

    🐛
    Rodrigo Fernandes

    🐛
    Roman Salvador

    💻 🐛 -
    Ronald Blaschke

    🐛 +
    Ronald Blaschke

    🐛
    Róbert Papp

    🐛
    Saikat Sengupta

    🐛
    Saksham Handu

    🐛
    Saladoc

    🐛
    Salesforce Bob Lightning

    🐛
    Sam Carlberg

    🐛 -
    Satoshi Kubo

    🐛 +
    Satoshi Kubo

    🐛
    Scott Kennedy

    🐛
    Scott Wells

    🐛 💻
    Scrsloota

    💻
    Sebastian Bögl

    🐛
    Sebastian Schuberth

    🐛
    Sebastian Schwarz

    🐛 -
    Sergey Gorbaty

    🐛 +
    Sergey Gorbaty

    🐛
    Sergey Kozlov

    🐛
    Sergey Yanzin

    💻 🐛
    Seth Wilcox

    💻
    Shubham

    💻 🐛
    Simon Xiao

    🐛
    Srinivasan Venkatachalam

    🐛 -
    Stanislav Gromov

    🐛 +
    Stanislav Gromov

    🐛
    Stanislav Myachenkov

    💻
    Stefan Birkner

    🐛
    Stefan Bohn

    🐛
    Stefan Endrullis

    🐛
    Stefan Klöss-Schuster

    🐛
    Stefan Wolf

    🐛 -
    Stephan H. Wissel

    🐛 +
    Stephan H. Wissel

    🐛
    Stephen

    🐛
    Stephen Friedrich

    🐛
    Steve Babula

    💻
    Stexxe

    🐛
    Stian Lågstad

    🐛
    StuartClayton5

    🐛 -
    Supun Arunoda

    🐛 +
    Supun Arunoda

    🐛
    Suren Abrahamyan

    🐛
    SwatiBGupta1110

    🐛
    SyedThoufich

    🐛
    Szymon Sasin

    🐛
    T-chuangxin

    🐛
    TERAI Atsuhiro

    🐛 -
    TIOBE Software

    💻 🐛 +
    TIOBE Software

    💻 🐛
    Taylor Smock

    🐛
    Techeira Damián

    💻 🐛
    Ted Husted

    🐛
    TehBakker

    🐛
    The Gitter Badger

    🐛
    Theodoor

    🐛 -
    Thiago Henrique Hüpner

    🐛 +
    Thiago Henrique Hüpner

    🐛
    Thibault Meyer

    🐛
    Thomas Güttler

    🐛
    Thomas Jones-Low

    🐛
    Thomas Smith

    💻 🐛
    ThrawnCA

    🐛
    Thunderforge

    💻 🐛 -
    Tim van der Lippe

    🐛 +
    Tim van der Lippe

    🐛
    Tobias Weimer

    💻 🐛
    Tom Daly

    🐛
    Tomer Figenblat

    🐛
    Tomi De Lucca

    💻 🐛
    Torsten Kleiber

    🐛
    TrackerSB

    🐛 -
    Ullrich Hafner

    🐛 +
    Ullrich Hafner

    🐛
    Utku Cuhadaroglu

    💻 🐛
    Valentin Brandl

    🐛
    Valeria

    🐛
    Vasily Anisimov

    🐛
    Vickenty Fesunov

    🐛
    Victor Noël

    🐛 -
    Vincent Galloy

    💻 +
    Vincent Galloy

    💻
    Vincent HUYNH

    🐛
    Vincent Maurin

    🐛
    Vincent Privat

    🐛
    Vishhwas

    🐛
    Vitaly

    🐛
    Vitaly Polonetsky

    🐛 -
    Vojtech Polivka

    🐛 +
    Vojtech Polivka

    🐛
    Vsevolod Zholobov

    🐛
    Vyom Yadav

    💻
    Wang Shidong

    🐛
    Waqas Ahmed

    🐛
    Wayne J. Earl

    🐛
    Wchenghui

    🐛 -
    Will Winder

    🐛 +
    Will Winder

    🐛
    William Brockhus

    💻 🐛
    Wilson Kurniawan

    🐛
    Wim Deblauwe

    🐛
    Woongsik Choi

    🐛
    XenoAmess

    💻 🐛
    Yang

    💻 -
    YaroslavTER

    🐛 +
    YaroslavTER

    🐛
    Young Chan

    💻 🐛
    YuJin Kim

    🐛
    Yuri Dolzhenko

    🐛
    Yurii Dubinka

    🐛
    Zoltan Farkas

    🐛
    Zustin

    🐛 -
    aaronhurst-google

    🐛 +
    aaronhurst-google

    🐛
    alexmodis

    🐛
    andreoss

    🐛
    andrey81inmd

    💻 🐛
    anicoara

    🐛
    arunprasathav

    🐛
    asiercamara

    🐛 -
    astillich-igniti

    💻 +
    astillich-igniti

    💻
    avesolovksyy

    🐛
    avishvat

    🐛
    avivmu

    🐛
    axelbarfod1

    🐛
    b-3-n

    🐛
    balbhadra9

    🐛 -
    base23de

    🐛 +
    base23de

    🐛
    bergander

    🐛
    berkam

    💻 🐛
    breizh31

    🐛
    caesarkim

    🐛
    carolyujing

    🐛
    cesares-basilico

    🐛 -
    chrite

    🐛 +
    chrite

    🐛
    cobratbq

    🐛
    coladict

    🐛
    cosmoJFH

    🐛
    cristalp

    🐛
    crunsk

    🐛
    cwholmes

    🐛 -
    cyberjj999

    🐛 +
    cyberjj999

    🐛
    cyw3

    🐛
    d1ss0nanz

    🐛
    danbrycefairsailcom

    🐛
    dariansanity

    🐛
    darrenmiliband

    🐛
    davidburstrom

    🐛 -
    dbirkman-paloalto

    🐛 +
    dbirkman-paloalto

    🐛
    deepak-patra

    🐛
    dependabot[bot]

    💻 🐛
    dinesh150

    🐛
    diziaq

    🐛
    dreaminpast123

    🐛
    duanyanan

    🐛 -
    dutt-sanjay

    🐛 +
    dutt-sanjay

    🐛
    dylanleung

    🐛
    dzeigler

    🐛
    ekkirala

    🐛
    emersonmoura

    🐛
    fairy

    🐛
    filiprafalowicz

    💻 -
    foxmason

    🐛 +
    foxmason

    🐛
    frankegabor

    🐛
    frankl

    🐛
    freafrea

    🐛
    fsapatin

    🐛
    gracia19

    🐛
    guo fei

    🐛 -
    gurmsc5

    🐛 +
    gurmsc5

    🐛
    gwilymatgearset

    💻 🐛
    haigsn

    🐛
    hemanshu070

    🐛
    henrik242

    🐛
    hongpuwu

    🐛
    hvbtup

    💻 🐛 -
    igniti GmbH

    🐛 +
    igniti GmbH

    🐛
    ilovezfs

    🐛
    itaigilo

    🐛
    jakivey32

    🐛
    jbennett2091

    🐛
    jcamerin

    🐛
    jkeener1

    🐛 -
    jmetertea

    🐛 +
    jmetertea

    🐛
    johnra2

    💻
    josemanuelrolon

    💻 🐛
    kabroxiko

    💻 🐛
    karwer

    🐛
    kaulonline

    🐛
    kdaemonv

    🐛 -
    kenji21

    💻 🐛 +
    kenji21

    💻 🐛
    kfranic

    🐛
    khalidkh

    🐛
    krzyk

    🐛
    lasselindqvist

    🐛
    lihuaib

    🐛
    lonelyma1021

    🐛 -
    lpeddy

    🐛 +
    lpeddy

    🐛
    lujiefsi

    💻
    lyriccoder

    🐛
    marcelmore

    🐛
    matchbox

    🐛
    matthiaskraaz

    🐛
    meandonlyme

    🐛 -
    mikesive

    🐛 +
    mikesive

    🐛
    milossesic

    🐛
    mriddell95

    🐛
    mrlzh

    🐛
    msloan

    🐛
    mucharlaravalika

    🐛
    mvenneman

    🐛 -
    nareshl119

    🐛 +
    nareshl119

    🐛
    nicolas-harraudeau-sonarsource

    🐛
    noerremark

    🐛
    novsirion

    🐛
    oggboy

    🐛
    oinume

    🐛
    orimarko

    💻 🐛 -
    pallavi agarwal

    🐛 +
    pallavi agarwal

    🐛
    parksungrin

    🐛
    patpatpat123

    🐛
    patriksevallius

    🐛
    pbrajesh1

    🐛
    phoenix384

    🐛
    piotrszymanski-sc

    💻 -
    plan3d

    🐛 +
    plan3d

    🐛
    poojasix

    🐛
    prabhushrikant

    🐛
    pujitha8783

    🐛
    r-r-a-j

    🐛
    raghujayjunk

    🐛
    rajeshveera

    🐛 -
    rajeswarreddy88

    🐛 +
    rajeswarreddy88

    🐛
    recdevs

    🐛
    reudismam

    💻 🐛
    rijkt

    🐛
    rillig-tk

    🐛
    rmohan20

    💻 🐛
    rxmicro

    🐛 -
    ryan-gustafson

    💻 🐛 +
    ryan-gustafson

    💻 🐛
    sabi0

    🐛
    scais

    🐛
    sebbASF

    🐛
    sergeygorbaty

    💻
    shilko2013

    🐛
    simeonKondr

    🐛 -
    snajberk

    🐛 +
    snajberk

    🐛
    sniperrifle2004

    🐛
    snuyanzin

    🐛 💻
    sratz

    🐛
    stonio

    🐛
    sturton

    💻 🐛
    sudharmohan

    🐛 -
    suruchidawar

    🐛 +
    suruchidawar

    🐛
    svenfinitiv

    🐛
    tashiscool

    🐛
    test-git-hook

    🐛
    testation21

    💻 🐛
    thanosa

    🐛
    tiandiyixian

    🐛 -
    tobwoerk

    🐛 +
    tobwoerk

    🐛
    tprouvot

    🐛
    trentchilders

    🐛
    triandicAnt

    🐛
    trishul14

    🐛
    tsui

    🐛
    winhkey

    🐛 -
    witherspore

    🐛 +
    witherspore

    🐛
    wjljack

    🐛
    wuchiuwong

    🐛
    xingsong

    🐛
    xioayuge

    🐛
    xnYi9wRezm

    💻 🐛
    xuanuy

    🐛 -
    xyf0921

    🐛 +
    xyf0921

    🐛
    yalechen-cyw3

    🐛
    yasuharu-sato

    🐛
    zenglian

    🐛
    zgrzyt93

    💻 🐛
    zh3ng

    🐛
    zt_soft

    🐛 -
    ztt79

    🐛 +
    ztt79

    🐛
    zzzzfeng

    🐛
    Árpád Magosányi

    🐛
    任贵杰

    🐛 From 4eb2471939d49fe325fb2af1f60bf8b7b31c733d Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 29 Apr 2022 12:01:29 +0200 Subject: [PATCH 158/180] Update gems Fixes Command injection in ruby-git (https://github.com/pmd/pmd/security/dependabot/21) --- Gemfile.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 453188095e..6c82745bd6 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -12,7 +12,7 @@ GEM concurrent-ruby (1.1.10) cork (0.3.0) colored2 (~> 3.1) - danger (8.5.0) + danger (8.6.1) claide (~> 1.0) claide-plugins (>= 0.9.2) colored2 (~> 3.1) @@ -56,9 +56,9 @@ GEM fugit (1.5.3) et-orbi (~> 1, >= 1.2.7) raabro (~> 1.4) - git (1.10.2) + git (1.11.0) rchardet (~> 1.8) - kramdown (2.3.2) + kramdown (2.4.0) rexml kramdown-parser-gfm (1.1.0) kramdown (~> 2.0) From 094bb1310ae011e484ad7c61dc1c66b0320c8f0d Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 29 Apr 2022 12:05:44 +0200 Subject: [PATCH 159/180] Update gems --- docs/Gemfile.lock | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock index 9c0396cead..48b6705d7b 100644 --- a/docs/Gemfile.lock +++ b/docs/Gemfile.lock @@ -1,7 +1,7 @@ GEM remote: https://rubygems.org/ specs: - activesupport (6.0.4.7) + activesupport (6.0.4.8) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) @@ -51,9 +51,9 @@ GEM ffi (1.15.5) forwardable-extended (2.6.0) gemoji (3.0.1) - github-pages (225) + github-pages (226) github-pages-health-check (= 1.17.9) - jekyll (= 3.9.0) + jekyll (= 3.9.2) jekyll-avatar (= 0.7.0) jekyll-coffeescript (= 1.1.1) jekyll-commonmark-ghpages (= 0.2.0) @@ -88,12 +88,12 @@ GEM jekyll-theme-time-machine (= 0.2.0) jekyll-titles-from-headings (= 0.5.3) jemoji (= 0.12.0) - kramdown (= 2.3.1) + kramdown (= 2.3.2) kramdown-parser-gfm (= 1.1.0) liquid (= 4.0.3) mercenary (~> 0.3) minima (= 2.5.1) - nokogiri (>= 1.12.5, < 2.0) + nokogiri (>= 1.13.4, < 2.0) rouge (= 3.26.0) terminal-table (~> 1.4) github-pages-health-check (1.17.9) @@ -108,7 +108,7 @@ GEM http_parser.rb (0.8.0) i18n (0.9.5) concurrent-ruby (~> 1.0) - jekyll (3.9.0) + jekyll (3.9.2) addressable (~> 2.4) colorator (~> 1.0) em-websocket (~> 0.5) @@ -216,7 +216,7 @@ GEM gemoji (~> 3.0) html-pipeline (~> 2.2) jekyll (>= 3.0, < 5.0) - kramdown (2.3.1) + kramdown (2.3.2) rexml kramdown-parser-gfm (1.1.0) kramdown (~> 2.0) From efcc58308604a8210677f11c6dd5ae816fb458dc Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 29 Apr 2022 12:22:44 +0200 Subject: [PATCH 160/180] [test] Improve test method name, display test method --- .../pmd/testframework/RuleTst.java | 1 + .../pmd/testframework/TestDescriptor.java | 3 ++- .../pmd/testframework/TestDescriptorTest.java | 27 +++++++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 pmd-test/src/test/java/net/sourceforge/pmd/testframework/TestDescriptorTest.java diff --git a/pmd-test/src/main/java/net/sourceforge/pmd/testframework/RuleTst.java b/pmd-test/src/main/java/net/sourceforge/pmd/testframework/RuleTst.java index 244ff01fd1..02981054d6 100644 --- a/pmd-test/src/main/java/net/sourceforge/pmd/testframework/RuleTst.java +++ b/pmd-test/src/main/java/net/sourceforge/pmd/testframework/RuleTst.java @@ -240,6 +240,7 @@ public abstract class RuleTst { System.out.println(" -> Expected messages: " + test.getExpectedMessages()); System.out.println(" -> Expected line numbers: " + test.getExpectedLineNumbers()); System.out.println("Test Method Name: " + test.getTestMethodName()); + System.out.println(" @org.junit.Test public void " + test.getTestMethodName() + "() {}"); System.out.println(); TextRenderer renderer = new TextRenderer(); renderer.setWriter(new StringWriter()); diff --git a/pmd-test/src/main/java/net/sourceforge/pmd/testframework/TestDescriptor.java b/pmd-test/src/main/java/net/sourceforge/pmd/testframework/TestDescriptor.java index 706f5f154b..8161ef4155 100644 --- a/pmd-test/src/main/java/net/sourceforge/pmd/testframework/TestDescriptor.java +++ b/pmd-test/src/main/java/net/sourceforge/pmd/testframework/TestDescriptor.java @@ -155,6 +155,7 @@ public class TestDescriptor { + "_" + getDescription() .replaceAll("\n|\r", "_") - .replaceAll("[\\.\\(\\)]|\\s", "_"); + .replaceAll("[^\\w\\d_$]", "_") + .replaceAll("\\s+", "_"); } } diff --git a/pmd-test/src/test/java/net/sourceforge/pmd/testframework/TestDescriptorTest.java b/pmd-test/src/test/java/net/sourceforge/pmd/testframework/TestDescriptorTest.java new file mode 100644 index 0000000000..ae8024ed13 --- /dev/null +++ b/pmd-test/src/test/java/net/sourceforge/pmd/testframework/TestDescriptorTest.java @@ -0,0 +1,27 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.testframework; + +import org.junit.Assert; +import org.junit.Test; + +import net.sourceforge.pmd.lang.rule.MockRule; + +public class TestDescriptorTest { + @Test + public void testMethodName() { + Assert.assertEquals("MockRule_1_Name", create("Name")); + Assert.assertEquals("MockRule_1_Tests_xyz", create("Tests xyz")); + Assert.assertEquals("MockRule_1_Tests_xyz__false_positive_", create("Tests xyz (false positive)")); + Assert.assertEquals("MockRule_1_Tests_xyz__123", create("Tests xyz #123")); + } + + private String create(String description) { + TestDescriptor descriptor = new TestDescriptor("foo", description, 0, + new MockRule("MockRule", "desc", "msg", "ruleset")); + descriptor.setNumberInDocument(1); + return descriptor.getTestMethodName(); + } +} From e4577c47ea9e71044aea6c773584fcdb98ef281a Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sat, 30 Apr 2022 09:18:09 +0200 Subject: [PATCH 161/180] [doc] Add user survey to release notes (#3814) --- docs/pages/release_notes.md | 9 +++++++++ docs/pages/release_notes_old.md | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index c3bcdfd719..e13519c596 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -14,6 +14,15 @@ This is a {{ site.pmd.release_type }} release. ### New and noteworthy +#### PMD User Survey + +Help shape the future of PMD by telling us how you use it. + +Our little survey is still open in case you didn't participate yet. +Please participate in our survey at . + +Thank you! + #### Support for HTML This version of PMD ships a new language module to support analyzing of HTML. diff --git a/docs/pages/release_notes_old.md b/docs/pages/release_notes_old.md index 22658ab447..4a5dfda4bf 100644 --- a/docs/pages/release_notes_old.md +++ b/docs/pages/release_notes_old.md @@ -14,6 +14,7 @@ This is a minor release. ### Table Of Contents * [New and noteworthy](#new-and-noteworthy) + * [PMD User Survey](#pmd-user-survey) * [Java 18 Support](#java-18-support) * [Better XML XPath support](#better-xml-xpath-support) * [New XPath functions](#new-xpath-functions) @@ -27,6 +28,14 @@ This is a minor release. ### New and noteworthy +#### PMD User Survey + +Help shape the future of PMD by telling us how you use it. + +Please participate in our survey at . + +Thank you! + #### Java 18 Support This release of PMD brings support for Java 18. There are no new standard language features. From 2212ff1fca16dd5e9d49d2d21fe9b7ecb0950b6f Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sat, 30 Apr 2022 09:25:31 +0200 Subject: [PATCH 162/180] Prepare pmd release 6.45.0 --- docs/_config.yml | 2 +- docs/pages/next_major_development.md | 12 ++++++++++++ docs/pages/release_notes.md | 5 +++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/docs/_config.yml b/docs/_config.yml index 68b6947986..9a81552a06 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -1,7 +1,7 @@ repository: pmd/pmd pmd: - version: 6.45.0-SNAPSHOT + version: 6.45.0 previous_version: 6.44.0 date: 30-April-2022 release_type: minor diff --git a/docs/pages/next_major_development.md b/docs/pages/next_major_development.md index e3a78af4e1..c95ad82a89 100644 --- a/docs/pages/next_major_development.md +++ b/docs/pages/next_major_development.md @@ -125,6 +125,18 @@ 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.45.0 + +##### Experimental APIs + +* Report has two new methods which allow limited mutations of a given report: + * {% jdoc !!core::Report#filterViolations(net.sourceforge.pmd.util.Predicate) %} creates a new report with + some violations removed with a given predicate based filter. + * {% jdoc !!core::Report#union(net.sourceforge.pmd.Report) %} can combine two reports into a single new Report. +* {% jdoc !!core::util.Predicate %} will be replaced in PMD7 with the standard Predicate interface from java8. +* The module `pmd-html` is entirely experimental right now. Anything in the package + `net.sourceforge.pmd.lang.html` should be used cautiously. + #### 6.44.0 ##### Deprecated API diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index e13519c596..1256c51f6e 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -114,5 +114,10 @@ missing features or bugs as new [issues](https://github.com/pmd/pmd/issues). * [#3938](https://github.com/pmd/pmd/pull/3938): \[java] Modify SimplifiedTernary to meet the missing case #3603 - [@VoidxHoshi](https://github.com/VoidxHoshi) * [#3943](https://github.com/pmd/pmd/pull/3943): chore: Set permissions for GitHub actions - [@naveensrinivasan](https://github.com/naveensrinivasan) +### Stats +* 97 commits +* 31 closed tickets & PRs +* Days since last release: 33 + {% endtocmaker %} From 1d2b40b3c0ad670c886a2e5c8ce62df467be3184 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sat, 30 Apr 2022 09:38:19 +0200 Subject: [PATCH 163/180] [maven-release-plugin] prepare release pmd_releases/6.45.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-html/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-modules/pmd-scala-common/pom.xml | 2 +- pmd-scala-modules/pmd-scala_2.12/pom.xml | 2 +- pmd-scala-modules/pmd-scala_2.13/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 | 6 +++--- 37 files changed, 39 insertions(+), 39 deletions(-) diff --git a/pmd-apex-jorje/pom.xml b/pmd-apex-jorje/pom.xml index 5697071519..2177615299 100644 --- a/pmd-apex-jorje/pom.xml +++ b/pmd-apex-jorje/pom.xml @@ -8,7 +8,7 @@ net.sourceforge.pmd pmd - 6.45.0-SNAPSHOT + 6.45.0 ../ diff --git a/pmd-apex/pom.xml b/pmd-apex/pom.xml index add57cacad..d8a22c3385 100644 --- a/pmd-apex/pom.xml +++ b/pmd-apex/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0-SNAPSHOT + 6.45.0 ../ diff --git a/pmd-core/pom.xml b/pmd-core/pom.xml index 3a5b8baa85..30bebc0fb7 100644 --- a/pmd-core/pom.xml +++ b/pmd-core/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0-SNAPSHOT + 6.45.0 ../ diff --git a/pmd-cpp/pom.xml b/pmd-cpp/pom.xml index 9a2e1f73d6..8fc1d92b24 100644 --- a/pmd-cpp/pom.xml +++ b/pmd-cpp/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0-SNAPSHOT + 6.45.0 ../ diff --git a/pmd-cs/pom.xml b/pmd-cs/pom.xml index 16a218ffcb..4260b044a0 100644 --- a/pmd-cs/pom.xml +++ b/pmd-cs/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0-SNAPSHOT + 6.45.0 ../ diff --git a/pmd-dart/pom.xml b/pmd-dart/pom.xml index 6cb0d6cf73..f476ab63d3 100644 --- a/pmd-dart/pom.xml +++ b/pmd-dart/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0-SNAPSHOT + 6.45.0 ../ diff --git a/pmd-dist/pom.xml b/pmd-dist/pom.xml index ca44f39d0b..099acacb6a 100644 --- a/pmd-dist/pom.xml +++ b/pmd-dist/pom.xml @@ -8,7 +8,7 @@ net.sourceforge.pmd pmd - 6.45.0-SNAPSHOT + 6.45.0 ../ diff --git a/pmd-doc/pom.xml b/pmd-doc/pom.xml index 120154f459..0a3c51fe72 100644 --- a/pmd-doc/pom.xml +++ b/pmd-doc/pom.xml @@ -8,7 +8,7 @@ net.sourceforge.pmd pmd - 6.45.0-SNAPSHOT + 6.45.0 ../ diff --git a/pmd-fortran/pom.xml b/pmd-fortran/pom.xml index 18a3d0d28a..6a03daecd1 100644 --- a/pmd-fortran/pom.xml +++ b/pmd-fortran/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0-SNAPSHOT + 6.45.0 ../ diff --git a/pmd-go/pom.xml b/pmd-go/pom.xml index ca4d6d83c7..dc9d4e5223 100644 --- a/pmd-go/pom.xml +++ b/pmd-go/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0-SNAPSHOT + 6.45.0 ../ diff --git a/pmd-groovy/pom.xml b/pmd-groovy/pom.xml index 61baf2b8c9..667c7227c2 100644 --- a/pmd-groovy/pom.xml +++ b/pmd-groovy/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0-SNAPSHOT + 6.45.0 ../ diff --git a/pmd-html/pom.xml b/pmd-html/pom.xml index 8e35a9cf2b..e04f55eb67 100644 --- a/pmd-html/pom.xml +++ b/pmd-html/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0-SNAPSHOT + 6.45.0 ../ diff --git a/pmd-java/pom.xml b/pmd-java/pom.xml index 246d4e724b..6bdda22f52 100644 --- a/pmd-java/pom.xml +++ b/pmd-java/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0-SNAPSHOT + 6.45.0 ../ diff --git a/pmd-java8/pom.xml b/pmd-java8/pom.xml index 318e38a082..be251fbad0 100644 --- a/pmd-java8/pom.xml +++ b/pmd-java8/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0-SNAPSHOT + 6.45.0 ../ diff --git a/pmd-javascript/pom.xml b/pmd-javascript/pom.xml index 417de06881..9607b1cca4 100644 --- a/pmd-javascript/pom.xml +++ b/pmd-javascript/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0-SNAPSHOT + 6.45.0 ../ diff --git a/pmd-jsp/pom.xml b/pmd-jsp/pom.xml index 4580722684..ccd9fe605d 100644 --- a/pmd-jsp/pom.xml +++ b/pmd-jsp/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0-SNAPSHOT + 6.45.0 ../ diff --git a/pmd-kotlin/pom.xml b/pmd-kotlin/pom.xml index 384e31e80b..ff01da1429 100644 --- a/pmd-kotlin/pom.xml +++ b/pmd-kotlin/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0-SNAPSHOT + 6.45.0 ../ diff --git a/pmd-lang-test/pom.xml b/pmd-lang-test/pom.xml index d138311451..2fb392ac97 100644 --- a/pmd-lang-test/pom.xml +++ b/pmd-lang-test/pom.xml @@ -12,7 +12,7 @@ net.sourceforge.pmd pmd - 6.45.0-SNAPSHOT + 6.45.0 ../ diff --git a/pmd-lua/pom.xml b/pmd-lua/pom.xml index aa86e5adab..30a6de5977 100644 --- a/pmd-lua/pom.xml +++ b/pmd-lua/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0-SNAPSHOT + 6.45.0 ../ diff --git a/pmd-matlab/pom.xml b/pmd-matlab/pom.xml index b6e09e11d1..a4c9c911b3 100644 --- a/pmd-matlab/pom.xml +++ b/pmd-matlab/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0-SNAPSHOT + 6.45.0 ../ diff --git a/pmd-modelica/pom.xml b/pmd-modelica/pom.xml index d4cd60d9b0..68b619bbbb 100644 --- a/pmd-modelica/pom.xml +++ b/pmd-modelica/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0-SNAPSHOT + 6.45.0 ../ diff --git a/pmd-objectivec/pom.xml b/pmd-objectivec/pom.xml index 0371376c9f..0c578a951a 100644 --- a/pmd-objectivec/pom.xml +++ b/pmd-objectivec/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0-SNAPSHOT + 6.45.0 ../ diff --git a/pmd-perl/pom.xml b/pmd-perl/pom.xml index e6fc6e13b9..4d46246e39 100644 --- a/pmd-perl/pom.xml +++ b/pmd-perl/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0-SNAPSHOT + 6.45.0 ../ diff --git a/pmd-php/pom.xml b/pmd-php/pom.xml index 06a17a3508..35bea733d2 100644 --- a/pmd-php/pom.xml +++ b/pmd-php/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0-SNAPSHOT + 6.45.0 ../ diff --git a/pmd-plsql/pom.xml b/pmd-plsql/pom.xml index 6874aceeab..b36d939c5b 100644 --- a/pmd-plsql/pom.xml +++ b/pmd-plsql/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0-SNAPSHOT + 6.45.0 ../ diff --git a/pmd-python/pom.xml b/pmd-python/pom.xml index 7e7337c031..2b3fa7f334 100644 --- a/pmd-python/pom.xml +++ b/pmd-python/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0-SNAPSHOT + 6.45.0 ../ diff --git a/pmd-ruby/pom.xml b/pmd-ruby/pom.xml index 683a2110fe..a611b8120d 100644 --- a/pmd-ruby/pom.xml +++ b/pmd-ruby/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0-SNAPSHOT + 6.45.0 ../ diff --git a/pmd-scala-modules/pmd-scala-common/pom.xml b/pmd-scala-modules/pmd-scala-common/pom.xml index edd18d9b0c..87052553b3 100644 --- a/pmd-scala-modules/pmd-scala-common/pom.xml +++ b/pmd-scala-modules/pmd-scala-common/pom.xml @@ -8,7 +8,7 @@ net.sourceforge.pmd pmd - 6.45.0-SNAPSHOT + 6.45.0 ../.. diff --git a/pmd-scala-modules/pmd-scala_2.12/pom.xml b/pmd-scala-modules/pmd-scala_2.12/pom.xml index f0371d6c2c..44921d47f5 100644 --- a/pmd-scala-modules/pmd-scala_2.12/pom.xml +++ b/pmd-scala-modules/pmd-scala_2.12/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd-scala-common - 6.45.0-SNAPSHOT + 6.45.0 ../pmd-scala-common diff --git a/pmd-scala-modules/pmd-scala_2.13/pom.xml b/pmd-scala-modules/pmd-scala_2.13/pom.xml index cfc266253a..b62798dae2 100644 --- a/pmd-scala-modules/pmd-scala_2.13/pom.xml +++ b/pmd-scala-modules/pmd-scala_2.13/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd-scala-common - 6.45.0-SNAPSHOT + 6.45.0 ../pmd-scala-common diff --git a/pmd-scala/pom.xml b/pmd-scala/pom.xml index 8be793a5d4..d1f1a19930 100644 --- a/pmd-scala/pom.xml +++ b/pmd-scala/pom.xml @@ -9,7 +9,7 @@ net.sourceforge.pmd pmd - 6.45.0-SNAPSHOT + 6.45.0 ../ diff --git a/pmd-swift/pom.xml b/pmd-swift/pom.xml index c714ee6a67..61c5a04d09 100644 --- a/pmd-swift/pom.xml +++ b/pmd-swift/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0-SNAPSHOT + 6.45.0 ../ diff --git a/pmd-test/pom.xml b/pmd-test/pom.xml index f6e41ef144..2d6a6cbc17 100644 --- a/pmd-test/pom.xml +++ b/pmd-test/pom.xml @@ -8,7 +8,7 @@ net.sourceforge.pmd pmd - 6.45.0-SNAPSHOT + 6.45.0 ../ diff --git a/pmd-visualforce/pom.xml b/pmd-visualforce/pom.xml index 3e2bd2cfac..9182fc71fd 100644 --- a/pmd-visualforce/pom.xml +++ b/pmd-visualforce/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0-SNAPSHOT + 6.45.0 ../ diff --git a/pmd-vm/pom.xml b/pmd-vm/pom.xml index dfbecb3abc..3328d08a20 100644 --- a/pmd-vm/pom.xml +++ b/pmd-vm/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0-SNAPSHOT + 6.45.0 ../ diff --git a/pmd-xml/pom.xml b/pmd-xml/pom.xml index c52f923011..e4e13d5708 100644 --- a/pmd-xml/pom.xml +++ b/pmd-xml/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0-SNAPSHOT + 6.45.0 ../ diff --git a/pom.xml b/pom.xml index b045e9e6e7..56fa392558 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 net.sourceforge.pmd pmd - 6.45.0-SNAPSHOT + 6.45.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.45.0 @@ -76,7 +76,7 @@ - 2022-03-27T15:01:59Z + 2022-04-30T07:25:51Z 7 From ec64315ad78ec8dc71a32fe83da62a100049ecdc Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sat, 30 Apr 2022 09:38:24 +0200 Subject: [PATCH 164/180] [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-html/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-modules/pmd-scala-common/pom.xml | 2 +- pmd-scala-modules/pmd-scala_2.12/pom.xml | 2 +- pmd-scala-modules/pmd-scala_2.13/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 | 6 +++--- 37 files changed, 39 insertions(+), 39 deletions(-) diff --git a/pmd-apex-jorje/pom.xml b/pmd-apex-jorje/pom.xml index 2177615299..778d8ff8f9 100644 --- a/pmd-apex-jorje/pom.xml +++ b/pmd-apex-jorje/pom.xml @@ -8,7 +8,7 @@ net.sourceforge.pmd pmd - 6.45.0 + 6.46.0-SNAPSHOT ../ diff --git a/pmd-apex/pom.xml b/pmd-apex/pom.xml index d8a22c3385..9c0e6b93a9 100644 --- a/pmd-apex/pom.xml +++ b/pmd-apex/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0 + 6.46.0-SNAPSHOT ../ diff --git a/pmd-core/pom.xml b/pmd-core/pom.xml index 30bebc0fb7..bd5ed97a91 100644 --- a/pmd-core/pom.xml +++ b/pmd-core/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0 + 6.46.0-SNAPSHOT ../ diff --git a/pmd-cpp/pom.xml b/pmd-cpp/pom.xml index 8fc1d92b24..3c72c91f0c 100644 --- a/pmd-cpp/pom.xml +++ b/pmd-cpp/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0 + 6.46.0-SNAPSHOT ../ diff --git a/pmd-cs/pom.xml b/pmd-cs/pom.xml index 4260b044a0..220db5815e 100644 --- a/pmd-cs/pom.xml +++ b/pmd-cs/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0 + 6.46.0-SNAPSHOT ../ diff --git a/pmd-dart/pom.xml b/pmd-dart/pom.xml index f476ab63d3..f49e28721e 100644 --- a/pmd-dart/pom.xml +++ b/pmd-dart/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0 + 6.46.0-SNAPSHOT ../ diff --git a/pmd-dist/pom.xml b/pmd-dist/pom.xml index 099acacb6a..66d4134964 100644 --- a/pmd-dist/pom.xml +++ b/pmd-dist/pom.xml @@ -8,7 +8,7 @@ net.sourceforge.pmd pmd - 6.45.0 + 6.46.0-SNAPSHOT ../ diff --git a/pmd-doc/pom.xml b/pmd-doc/pom.xml index 0a3c51fe72..db23e84ae7 100644 --- a/pmd-doc/pom.xml +++ b/pmd-doc/pom.xml @@ -8,7 +8,7 @@ net.sourceforge.pmd pmd - 6.45.0 + 6.46.0-SNAPSHOT ../ diff --git a/pmd-fortran/pom.xml b/pmd-fortran/pom.xml index 6a03daecd1..d41d7c00db 100644 --- a/pmd-fortran/pom.xml +++ b/pmd-fortran/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0 + 6.46.0-SNAPSHOT ../ diff --git a/pmd-go/pom.xml b/pmd-go/pom.xml index dc9d4e5223..2b222b6828 100644 --- a/pmd-go/pom.xml +++ b/pmd-go/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0 + 6.46.0-SNAPSHOT ../ diff --git a/pmd-groovy/pom.xml b/pmd-groovy/pom.xml index 667c7227c2..0ee77da952 100644 --- a/pmd-groovy/pom.xml +++ b/pmd-groovy/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0 + 6.46.0-SNAPSHOT ../ diff --git a/pmd-html/pom.xml b/pmd-html/pom.xml index e04f55eb67..60d5d84c58 100644 --- a/pmd-html/pom.xml +++ b/pmd-html/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0 + 6.46.0-SNAPSHOT ../ diff --git a/pmd-java/pom.xml b/pmd-java/pom.xml index 6bdda22f52..b85810aaeb 100644 --- a/pmd-java/pom.xml +++ b/pmd-java/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0 + 6.46.0-SNAPSHOT ../ diff --git a/pmd-java8/pom.xml b/pmd-java8/pom.xml index be251fbad0..789472025c 100644 --- a/pmd-java8/pom.xml +++ b/pmd-java8/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0 + 6.46.0-SNAPSHOT ../ diff --git a/pmd-javascript/pom.xml b/pmd-javascript/pom.xml index 9607b1cca4..d4256cf9bc 100644 --- a/pmd-javascript/pom.xml +++ b/pmd-javascript/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0 + 6.46.0-SNAPSHOT ../ diff --git a/pmd-jsp/pom.xml b/pmd-jsp/pom.xml index ccd9fe605d..baef67d1fc 100644 --- a/pmd-jsp/pom.xml +++ b/pmd-jsp/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0 + 6.46.0-SNAPSHOT ../ diff --git a/pmd-kotlin/pom.xml b/pmd-kotlin/pom.xml index ff01da1429..fb25975fec 100644 --- a/pmd-kotlin/pom.xml +++ b/pmd-kotlin/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0 + 6.46.0-SNAPSHOT ../ diff --git a/pmd-lang-test/pom.xml b/pmd-lang-test/pom.xml index 2fb392ac97..c657cdd6b8 100644 --- a/pmd-lang-test/pom.xml +++ b/pmd-lang-test/pom.xml @@ -12,7 +12,7 @@ net.sourceforge.pmd pmd - 6.45.0 + 6.46.0-SNAPSHOT ../ diff --git a/pmd-lua/pom.xml b/pmd-lua/pom.xml index 30a6de5977..169eee58b6 100644 --- a/pmd-lua/pom.xml +++ b/pmd-lua/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0 + 6.46.0-SNAPSHOT ../ diff --git a/pmd-matlab/pom.xml b/pmd-matlab/pom.xml index a4c9c911b3..278632df19 100644 --- a/pmd-matlab/pom.xml +++ b/pmd-matlab/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0 + 6.46.0-SNAPSHOT ../ diff --git a/pmd-modelica/pom.xml b/pmd-modelica/pom.xml index 68b619bbbb..39ace11468 100644 --- a/pmd-modelica/pom.xml +++ b/pmd-modelica/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0 + 6.46.0-SNAPSHOT ../ diff --git a/pmd-objectivec/pom.xml b/pmd-objectivec/pom.xml index 0c578a951a..fda16dfe0b 100644 --- a/pmd-objectivec/pom.xml +++ b/pmd-objectivec/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0 + 6.46.0-SNAPSHOT ../ diff --git a/pmd-perl/pom.xml b/pmd-perl/pom.xml index 4d46246e39..53060f5e27 100644 --- a/pmd-perl/pom.xml +++ b/pmd-perl/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0 + 6.46.0-SNAPSHOT ../ diff --git a/pmd-php/pom.xml b/pmd-php/pom.xml index 35bea733d2..21fee6046d 100644 --- a/pmd-php/pom.xml +++ b/pmd-php/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0 + 6.46.0-SNAPSHOT ../ diff --git a/pmd-plsql/pom.xml b/pmd-plsql/pom.xml index b36d939c5b..7eb1da955f 100644 --- a/pmd-plsql/pom.xml +++ b/pmd-plsql/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0 + 6.46.0-SNAPSHOT ../ diff --git a/pmd-python/pom.xml b/pmd-python/pom.xml index 2b3fa7f334..3170b0ba55 100644 --- a/pmd-python/pom.xml +++ b/pmd-python/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0 + 6.46.0-SNAPSHOT ../ diff --git a/pmd-ruby/pom.xml b/pmd-ruby/pom.xml index a611b8120d..35fb4b5753 100644 --- a/pmd-ruby/pom.xml +++ b/pmd-ruby/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0 + 6.46.0-SNAPSHOT ../ diff --git a/pmd-scala-modules/pmd-scala-common/pom.xml b/pmd-scala-modules/pmd-scala-common/pom.xml index 87052553b3..949c221a80 100644 --- a/pmd-scala-modules/pmd-scala-common/pom.xml +++ b/pmd-scala-modules/pmd-scala-common/pom.xml @@ -8,7 +8,7 @@ net.sourceforge.pmd pmd - 6.45.0 + 6.46.0-SNAPSHOT ../.. diff --git a/pmd-scala-modules/pmd-scala_2.12/pom.xml b/pmd-scala-modules/pmd-scala_2.12/pom.xml index 44921d47f5..244b9c52ab 100644 --- a/pmd-scala-modules/pmd-scala_2.12/pom.xml +++ b/pmd-scala-modules/pmd-scala_2.12/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd-scala-common - 6.45.0 + 6.46.0-SNAPSHOT ../pmd-scala-common diff --git a/pmd-scala-modules/pmd-scala_2.13/pom.xml b/pmd-scala-modules/pmd-scala_2.13/pom.xml index b62798dae2..1206d12f5d 100644 --- a/pmd-scala-modules/pmd-scala_2.13/pom.xml +++ b/pmd-scala-modules/pmd-scala_2.13/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd-scala-common - 6.45.0 + 6.46.0-SNAPSHOT ../pmd-scala-common diff --git a/pmd-scala/pom.xml b/pmd-scala/pom.xml index d1f1a19930..211a199e81 100644 --- a/pmd-scala/pom.xml +++ b/pmd-scala/pom.xml @@ -9,7 +9,7 @@ net.sourceforge.pmd pmd - 6.45.0 + 6.46.0-SNAPSHOT ../ diff --git a/pmd-swift/pom.xml b/pmd-swift/pom.xml index 61c5a04d09..dcfe7b980a 100644 --- a/pmd-swift/pom.xml +++ b/pmd-swift/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0 + 6.46.0-SNAPSHOT ../ diff --git a/pmd-test/pom.xml b/pmd-test/pom.xml index 2d6a6cbc17..6922c448a0 100644 --- a/pmd-test/pom.xml +++ b/pmd-test/pom.xml @@ -8,7 +8,7 @@ net.sourceforge.pmd pmd - 6.45.0 + 6.46.0-SNAPSHOT ../ diff --git a/pmd-visualforce/pom.xml b/pmd-visualforce/pom.xml index 9182fc71fd..deb955ece6 100644 --- a/pmd-visualforce/pom.xml +++ b/pmd-visualforce/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0 + 6.46.0-SNAPSHOT ../ diff --git a/pmd-vm/pom.xml b/pmd-vm/pom.xml index 3328d08a20..6faab019c3 100644 --- a/pmd-vm/pom.xml +++ b/pmd-vm/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0 + 6.46.0-SNAPSHOT ../ diff --git a/pmd-xml/pom.xml b/pmd-xml/pom.xml index e4e13d5708..407bb1aa7f 100644 --- a/pmd-xml/pom.xml +++ b/pmd-xml/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.45.0 + 6.46.0-SNAPSHOT ../ diff --git a/pom.xml b/pom.xml index 56fa392558..c986b3a6fd 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 net.sourceforge.pmd pmd - 6.45.0 + 6.46.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.45.0 + HEAD @@ -76,7 +76,7 @@ - 2022-04-30T07:25:51Z + 2022-04-30T07:38:24Z 7 From b5dfd05c00324ba551c837da0c818ca39a90a038 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sat, 30 Apr 2022 09:41:05 +0200 Subject: [PATCH 165/180] Prepare next development version [skip ci] --- docs/_config.yml | 6 +- docs/pages/release_notes.md | 99 ------------------------- docs/pages/release_notes_old.md | 126 ++++++++++++++++++++++++++++++++ 3 files changed, 129 insertions(+), 102 deletions(-) diff --git a/docs/_config.yml b/docs/_config.yml index 9a81552a06..211a788da0 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -1,9 +1,9 @@ repository: pmd/pmd pmd: - version: 6.45.0 - previous_version: 6.44.0 - date: 30-April-2022 + version: 6.46.0-SNAPSHOT + previous_version: 6.45.0 + date: 28-May-2022 release_type: minor # release types: major, minor, bugfix diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 1256c51f6e..b8f8783555 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -14,110 +14,11 @@ This is a {{ site.pmd.release_type }} release. ### New and noteworthy -#### PMD User Survey - -Help shape the future of PMD by telling us how you use it. - -Our little survey is still open in case you didn't participate yet. -Please participate in our survey at . - -Thank you! - -#### Support for HTML - -This version of PMD ships a new language module to support analyzing of HTML. -Support for HTML is experimental and might change without notice. -The language implementation is not complete yet and the AST doesn't look -well for text nodes and comment nodes and might be changed in the future. -You can write your own rules, but we don't guarantee that the rules work with -the next (minor) version of PMD without adjustments. - -Please give us feedback about how practical this new language is in -[discussions](https://github.com/pmd/pmd/discussions). Please report -missing features or bugs as new [issues](https://github.com/pmd/pmd/issues). - -#### New rules - -* The HTML rule {% rule html/bestpractices/AvoidInlineStyles %} finds elements which use a style attribute. - In order to help maintaining a webpage it is considered good practice to separate content and styles. Instead - of inline styles one should use CSS files and classes. - -```xml - -``` - -* The HTML rule {% rule html/bestpractices/UnnecessaryTypeAttribute %} finds "link" and "script" elements which - still have a "type" attribute. This is not necessary anymore since modern browsers automatically use CSS and - JavaScript. - -```xml - -``` - -* The HTML rule {% rule html/bestpractices/UseAltAttributeForImages %} finds "img" elements without an "alt" - attribute. An alternate text should always be provided in order to help screen readers. - -```xml - -``` - -#### Modified rules - -* The Java rule {% rule java/bestpractices/UnusedPrivateField %} has a new property `ignoredFieldNames`. - The default ignores serialization-specific fields (eg `serialVersionUID`). - The property can be used to ignore more fields based on their name. - Note that the rule used to ignore fields named `IDENT`, but doesn't anymore (add this value to the property to restore the old behaviour). - ### Fixed Issues -* core - * [#3792](https://github.com/pmd/pmd/issues/3792): \[core] Allow to filter violations in Report - * [#3881](https://github.com/pmd/pmd/issues/3881): \[core] SARIF renderer depends on platform default encoding - * [#3882](https://github.com/pmd/pmd/pull/3882): \[core] Fix AssertionError about exhaustive switch - * [#3884](https://github.com/pmd/pmd/issues/3884): \[core] XML report via ant task contains XML header twice - * [#3896](https://github.com/pmd/pmd/pull/3896): \[core] Fix ast-dump CLI when reading from stdin -* doc - * [#2505](https://github.com/pmd/pmd/issues/2505): \[doc] Improve side bar to show release date -* java - * [#3068](https://github.com/pmd/pmd/issues/3068): \[java] Some tests should not depend on real rules - * [#3889](https://github.com/pmd/pmd/pull/3889): \[java] Catch LinkageError in UselessOverridingMethodRule -* java-bestpractices - * [#3910](https://github.com/pmd/pmd/pull/3910): \[java] UnusedPrivateField - Allow the ignored fieldnames to be configurable - * [#1185](https://github.com/pmd/pmd/issues/1185): \[java] ArrayIsStoredDirectly false positive with field access - * [#1474](https://github.com/pmd/pmd/issues/1474): \[java] ArrayIsStoredDirectly false positive with method call - * [#3879](https://github.com/pmd/pmd/issues/3879) \[java] ArrayIsStoredDirectly reports duplicated violation - * [#3929](https://github.com/pmd/pmd/issues/3929): \[java] ArrayIsStoredDirectly should report the assignment rather than formal parameter -* java-design - * [#3603](https://github.com/pmd/pmd/issues/3603): \[java] SimplifiedTernary: no violation for 'condition ? true : false' case -* java-performance - * [#3867](https://github.com/pmd/pmd/issues/3867): \[java] UseArraysAsList with method call -* plsql - * [#3687](https://github.com/pmd/pmd/issues/3687): \[plsql] Parsing exception EXECUTE IMMEDIATE l_sql BULK COLLECT INTO statement - * [#3706](https://github.com/pmd/pmd/issues/3706): \[plsql] Parsing exception CURSOR statement with parenthesis groupings ### API Changes -#### Experimental APIs - -* Report has two new methods which allow limited mutations of a given report: - * {% jdoc !!core::Report#filterViolations(net.sourceforge.pmd.util.Predicate) %} creates a new report with - some violations removed with a given predicate based filter. - * {% jdoc !!core::Report#union(net.sourceforge.pmd.Report) %} can combine two reports into a single new Report. -* {% jdoc !!core::util.Predicate %} will be replaced in PMD7 with the standard Predicate interface from java8. -* The module `pmd-html` is entirely experimental right now. Anything in the package - `net.sourceforge.pmd.lang.html` should be used cautiously. - ### External Contributions -* [#3883](https://github.com/pmd/pmd/pull/3883): \[doc] Improve side bar by Adding Release Date - [@jasonqiu98](https://github.com/jasonqiu98) -* [#3910](https://github.com/pmd/pmd/pull/3910): \[java] UnusedPrivateField - Allow the ignored fieldnames to be configurable - [@laoseth](https://github.com/laoseth) -* [#3928](https://github.com/pmd/pmd/pull/3928): \[plsql] Fix plsql parsing error in parenthesis groups - [@LiGaOg](https://github.com/LiGaOg) -* [#3935](https://github.com/pmd/pmd/pull/3935): \[plsql] Fix parser exception in EXECUTE IMMEDIATE BULK COLLECT #3687 - [@Scrsloota](https://github.com/Scrsloota) -* [#3938](https://github.com/pmd/pmd/pull/3938): \[java] Modify SimplifiedTernary to meet the missing case #3603 - [@VoidxHoshi](https://github.com/VoidxHoshi) -* [#3943](https://github.com/pmd/pmd/pull/3943): chore: Set permissions for GitHub actions - [@naveensrinivasan](https://github.com/naveensrinivasan) - -### Stats -* 97 commits -* 31 closed tickets & PRs -* Days since last release: 33 {% endtocmaker %} diff --git a/docs/pages/release_notes_old.md b/docs/pages/release_notes_old.md index 4a5dfda4bf..1d546c49c1 100644 --- a/docs/pages/release_notes_old.md +++ b/docs/pages/release_notes_old.md @@ -5,6 +5,132 @@ permalink: pmd_release_notes_old.html Previous versions of PMD can be downloaded here: https://github.com/pmd/pmd/releases +## 30-April-2022 - 6.45.0 + +The PMD team is pleased to announce PMD 6.45.0. + +This is a minor release. + +### Table Of Contents + +* [New and noteworthy](#new-and-noteworthy) + * [PMD User Survey](#pmd-user-survey) + * [Support for HTML](#support-for-html) + * [New rules](#new-rules) + * [Modified rules](#modified-rules) +* [Fixed Issues](#fixed-issues) +* [API Changes](#api-changes) + * [Experimental APIs](#experimental-apis) +* [External Contributions](#external-contributions) +* [Stats](#stats) + +### New and noteworthy + +#### PMD User Survey + +Help shape the future of PMD by telling us how you use it. + +Our little survey is still open in case you didn't participate yet. +Please participate in our survey at . + +Thank you! + +#### Support for HTML + +This version of PMD ships a new language module to support analyzing of HTML. +Support for HTML is experimental and might change without notice. +The language implementation is not complete yet and the AST doesn't look +well for text nodes and comment nodes and might be changed in the future. +You can write your own rules, but we don't guarantee that the rules work with +the next (minor) version of PMD without adjustments. + +Please give us feedback about how practical this new language is in +[discussions](https://github.com/pmd/pmd/discussions). Please report +missing features or bugs as new [issues](https://github.com/pmd/pmd/issues). + +#### New rules + +* The HTML rule [`AvoidInlineStyles`](https://pmd.github.io/pmd-6.45.0/pmd_rules_html_bestpractices.html#avoidinlinestyles) finds elements which use a style attribute. + In order to help maintaining a webpage it is considered good practice to separate content and styles. Instead + of inline styles one should use CSS files and classes. + +```xml + +``` + +* The HTML rule [`UnnecessaryTypeAttribute`](https://pmd.github.io/pmd-6.45.0/pmd_rules_html_bestpractices.html#unnecessarytypeattribute) finds "link" and "script" elements which + still have a "type" attribute. This is not necessary anymore since modern browsers automatically use CSS and + JavaScript. + +```xml + +``` + +* The HTML rule [`UseAltAttributeForImages`](https://pmd.github.io/pmd-6.45.0/pmd_rules_html_bestpractices.html#usealtattributeforimages) finds "img" elements without an "alt" + attribute. An alternate text should always be provided in order to help screen readers. + +```xml + +``` + +#### Modified rules + +* The Java rule [`UnusedPrivateField`](https://pmd.github.io/pmd-6.45.0/pmd_rules_java_bestpractices.html#unusedprivatefield) has a new property `ignoredFieldNames`. + The default ignores serialization-specific fields (eg `serialVersionUID`). + The property can be used to ignore more fields based on their name. + Note that the rule used to ignore fields named `IDENT`, but doesn't anymore (add this value to the property to restore the old behaviour). + +### Fixed Issues +* core + * [#3792](https://github.com/pmd/pmd/issues/3792): \[core] Allow to filter violations in Report + * [#3881](https://github.com/pmd/pmd/issues/3881): \[core] SARIF renderer depends on platform default encoding + * [#3882](https://github.com/pmd/pmd/pull/3882): \[core] Fix AssertionError about exhaustive switch + * [#3884](https://github.com/pmd/pmd/issues/3884): \[core] XML report via ant task contains XML header twice + * [#3896](https://github.com/pmd/pmd/pull/3896): \[core] Fix ast-dump CLI when reading from stdin +* doc + * [#2505](https://github.com/pmd/pmd/issues/2505): \[doc] Improve side bar to show release date +* java + * [#3068](https://github.com/pmd/pmd/issues/3068): \[java] Some tests should not depend on real rules + * [#3889](https://github.com/pmd/pmd/pull/3889): \[java] Catch LinkageError in UselessOverridingMethodRule +* java-bestpractices + * [#3910](https://github.com/pmd/pmd/pull/3910): \[java] UnusedPrivateField - Allow the ignored fieldnames to be configurable + * [#1185](https://github.com/pmd/pmd/issues/1185): \[java] ArrayIsStoredDirectly false positive with field access + * [#1474](https://github.com/pmd/pmd/issues/1474): \[java] ArrayIsStoredDirectly false positive with method call + * [#3879](https://github.com/pmd/pmd/issues/3879) \[java] ArrayIsStoredDirectly reports duplicated violation + * [#3929](https://github.com/pmd/pmd/issues/3929): \[java] ArrayIsStoredDirectly should report the assignment rather than formal parameter +* java-design + * [#3603](https://github.com/pmd/pmd/issues/3603): \[java] SimplifiedTernary: no violation for 'condition ? true : false' case +* java-performance + * [#3867](https://github.com/pmd/pmd/issues/3867): \[java] UseArraysAsList with method call +* plsql + * [#3687](https://github.com/pmd/pmd/issues/3687): \[plsql] Parsing exception EXECUTE IMMEDIATE l_sql BULK COLLECT INTO statement + * [#3706](https://github.com/pmd/pmd/issues/3706): \[plsql] Parsing exception CURSOR statement with parenthesis groupings + +### API Changes + +#### Experimental APIs + +* Report has two new methods which allow limited mutations of a given report: + * Report#filterViolations creates a new report with + some violations removed with a given predicate based filter. + * Report#union can combine two reports into a single new Report. +* net.sourceforge.pmd.util.Predicate will be replaced in PMD7 with the standard Predicate interface from java8. +* The module `pmd-html` is entirely experimental right now. Anything in the package + `net.sourceforge.pmd.lang.html` should be used cautiously. + +### External Contributions +* [#3883](https://github.com/pmd/pmd/pull/3883): \[doc] Improve side bar by Adding Release Date - [@jasonqiu98](https://github.com/jasonqiu98) +* [#3910](https://github.com/pmd/pmd/pull/3910): \[java] UnusedPrivateField - Allow the ignored fieldnames to be configurable - [@laoseth](https://github.com/laoseth) +* [#3928](https://github.com/pmd/pmd/pull/3928): \[plsql] Fix plsql parsing error in parenthesis groups - [@LiGaOg](https://github.com/LiGaOg) +* [#3935](https://github.com/pmd/pmd/pull/3935): \[plsql] Fix parser exception in EXECUTE IMMEDIATE BULK COLLECT #3687 - [@Scrsloota](https://github.com/Scrsloota) +* [#3938](https://github.com/pmd/pmd/pull/3938): \[java] Modify SimplifiedTernary to meet the missing case #3603 - [@VoidxHoshi](https://github.com/VoidxHoshi) +* [#3943](https://github.com/pmd/pmd/pull/3943): chore: Set permissions for GitHub actions - [@naveensrinivasan](https://github.com/naveensrinivasan) + +### Stats +* 97 commits +* 31 closed tickets & PRs +* Days since last release: 33 + ## 27-March-2022 - 6.44.0 The PMD team is pleased to announce PMD 6.44.0. From 86891b0c6d143da49f15d738b19192e086e9286c Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sat, 30 Apr 2022 10:27:59 +0200 Subject: [PATCH 166/180] Bump pmd from 6.44.0 to 6.45.0 --- pom.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index c986b3a6fd..08d245b8ff 100644 --- a/pom.xml +++ b/pom.xml @@ -406,22 +406,22 @@ net.sourceforge.pmd pmd-core - 6.44.0 + 6.45.0 net.sourceforge.pmd pmd-java - 6.44.0 + 6.45.0 net.sourceforge.pmd pmd-jsp - 6.44.0 + 6.45.0 net.sourceforge.pmd pmd-javascript - 6.44.0 + 6.45.0 From 772ccb3386c8203b0e180291472f1134476630a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sat, 30 Apr 2022 14:03:59 +0200 Subject: [PATCH 167/180] Cleanups in Chars Co-authored-by: Andreas Dangel --- .../java/net/sourceforge/pmd/lang/document/Chars.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java index bb1cf4265c..13be61a02e 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java @@ -103,8 +103,8 @@ public final class Chars implements CharSequence { } /** - * Copies 'len' characters from index 'from' into the given array, - * starting at 'off'. + * Copies 'count' characters from index 'srcBegin' into the given array, + * starting at 'dstBegin'. * * @param srcBegin Start offset in this CharSequence * @param cbuf Character array @@ -177,7 +177,7 @@ public final class Chars implements CharSequence { } final char fst = searched.charAt(0); - int strpos = str.indexOf(fst, start + fromIndex); + int strpos = str.indexOf(fst, idx(fromIndex)); while (strpos != NOT_FOUND && strpos <= max) { if (str.startsWith(searched, strpos)) { return strpos - start; @@ -252,7 +252,7 @@ public final class Chars implements CharSequence { if (fromIndex < 0 || fromIndex + 1 > len) { return false; } - return str.charAt(start + fromIndex) == prefix; + return str.charAt(idx(fromIndex)) == prefix; } /** @@ -446,6 +446,9 @@ public final class Chars implements CharSequence { * Returns the substring between the given offsets. * given length. * + *

    Note: Unlike slice or subSequence, this method will create a new String which involves copying the + * backing char array. Don't use it unnecessarily. + * * @param start Start offset ({@code 0 <= start < this.length()}) * @param end End offset ({@code start <= end <= this.length()}) * From 7ed2b6610ae8bb7aca8200922d74ac731815227c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sat, 30 Apr 2022 14:11:16 +0200 Subject: [PATCH 168/180] Stop using long to mask line/col --- .../pmd/lang/document/RootTextDocument.java | 20 ++++++++----------- .../lang/document/SourceCodePositioner.java | 19 +++--------------- .../document/SourceCodePositionerTest.java | 12 ----------- 3 files changed, 11 insertions(+), 40 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/RootTextDocument.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/RootTextDocument.java index dae3fed124..873fba75c5 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/RootTextDocument.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/RootTextDocument.java @@ -74,27 +74,23 @@ final class RootTextDocument extends BaseCloseable implements TextDocument { // We use longs to return both numbers at the same time // This limits us to 2 billion lines or columns, which is FINE - long bpos = positioner.lineColFromOffset(region.getStartOffset(), true); - long epos = region.isEmpty() ? bpos - : positioner.lineColFromOffset(region.getEndOffset(), false); + TextPos2d bpos = positioner.lineColFromOffset(region.getStartOffset(), true); + TextPos2d epos = region.isEmpty() ? bpos + : positioner.lineColFromOffset(region.getEndOffset(), false); return new FileLocation( fileName, - SourceCodePositioner.unmaskLine(bpos), - SourceCodePositioner.unmaskCol(bpos), - SourceCodePositioner.unmaskLine(epos), - SourceCodePositioner.unmaskCol(epos), + bpos.getLine(), + bpos.getColumn(), + epos.getLine(), + epos.getColumn(), region ); } @Override public TextPos2d lineColumnAtOffset(int offset, boolean inclusive) { - long longPos = content.getPositioner().lineColFromOffset(offset, inclusive); - return TextPos2d.pos2d( - SourceCodePositioner.unmaskLine(longPos), - SourceCodePositioner.unmaskCol(longPos) - ); + return content.getPositioner().lineColFromOffset(offset, inclusive); } @Override diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/SourceCodePositioner.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/SourceCodePositioner.java index ed4301b827..424f8db48f 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/SourceCodePositioner.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/SourceCodePositioner.java @@ -37,7 +37,7 @@ final class SourceCodePositioner { return lineOffsets; } - long lineColFromOffset(int offset, boolean inclusive) { + TextPos2d lineColFromOffset(int offset, boolean inclusive) { AssertionUtil.requireInInclusiveRange("offset", offset, 0, sourceCodeLength); int line = searchLineOffset(offset); @@ -51,23 +51,10 @@ final class SourceCodePositioner { // handle. This is because an offset may be interpreted as the index // of a character, or the caret position between two characters. This // is relevant when building text regions, to respect inclusivity, etc. - return maskLineCol(lineIdx, getLastColumnOfLine(lineIdx)); + return TextPos2d.pos2d(lineIdx, getLastColumnOfLine(lineIdx)); } - return maskLineCol(line, 1 + offset - lineOffsets[lineIdx]); - } - - // test only - static long maskLineCol(int line, int col) { - return (long) line << 32 | (long) col; - } - - static int unmaskLine(long lineCol) { - return (int) (lineCol >> 32); - } - - static int unmaskCol(long lineCol) { - return (int) lineCol; + return TextPos2d.pos2d(line, 1 + offset - lineOffsets[lineIdx]); } /** diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/SourceCodePositionerTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/SourceCodePositionerTest.java index 26a3c987c2..7aa7c89ab1 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/SourceCodePositionerTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/SourceCodePositionerTest.java @@ -153,16 +153,4 @@ public class SourceCodePositionerTest { assertArrayEquals(new int[] { 0, 41, 50, 51 }, positioner.getLineOffsets()); } - @Test - public void longOffsetMasking() { - assertMasking(1, 4); - assertMasking(Integer.MAX_VALUE, Integer.MAX_VALUE); - } - - private void assertMasking(int line, int col) { - long l = SourceCodePositioner.maskLineCol(line, col); - assertEquals(line, SourceCodePositioner.unmaskLine(l)); - assertEquals(col, SourceCodePositioner.unmaskCol(l)); - } - } From 1b7560dd7c3b6ec361048327b7ad748a87d06423 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sat, 30 Apr 2022 14:25:16 +0200 Subject: [PATCH 169/180] Fix HTML module Requires Chars#newReader to support marks --- .../sourceforge/pmd/lang/document/Chars.java | 104 ++++++++++++------ .../pmd/lang/html/ast/ASTHtmlDocument.java | 2 +- .../pmd/lang/html/ast/AbstractHtmlNode.java | 16 ++- .../pmd/lang/html/ast/HtmlParser.java | 5 +- .../pmd/lang/html/ast/HtmlTokenizer.java | 35 +++--- .../pmd/lang/html/ast/HtmlTreeBuilder.java | 6 +- .../pmd/lang/html/ast/LineNumbers.java | 19 ++-- .../pmd/lang/html/HtmlJavaRuleTest.java | 19 +--- .../pmd/lang/html/HtmlParsingHelper.java | 24 ++++ .../pmd/lang/html/HtmlXPathRuleTest.java | 41 +++---- 10 files changed, 155 insertions(+), 116 deletions(-) create mode 100644 pmd-html/src/test/java/net/sourceforge/pmd/lang/html/HtmlParsingHelper.java diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java index 13be61a02e..a2318f5876 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java @@ -446,8 +446,9 @@ public final class Chars implements CharSequence { * Returns the substring between the given offsets. * given length. * - *

    Note: Unlike slice or subSequence, this method will create a new String which involves copying the - * backing char array. Don't use it unnecessarily. + *

    Note: Unlike slice or subSequence, this method will create a + * new String which involves copying the backing char array. Don't + * use it unnecessarily. * * @param start Start offset ({@code 0 <= start < this.length()}) * @param end End offset ({@code start <= end <= this.length()}) @@ -591,40 +592,79 @@ public final class Chars implements CharSequence { * Returns a new reader for the whole contents of this char sequence. */ public Reader newReader() { - return new Reader() { - private int pos = start; - private final int max = start + len; + return new CharsReader(this); + } - @Override - public int read(char @NonNull [] cbuf, int off, int len) { - if (len < 0 || off < 0 || off + len > cbuf.length) { - throw new IndexOutOfBoundsException(); - } - if (pos >= max) { - return NOT_FOUND; - } - int toRead = Integer.min(max - pos, len); - str.getChars(pos, pos + toRead, cbuf, off); - pos += toRead; - return toRead; - } + private static final class CharsReader extends Reader { - @Override - public int read() { - return pos >= max ? NOT_FOUND : str.charAt(pos++); - } + private Chars chars; + private int pos; + private final int max; + private int mark = -1; - @Override - public long skip(long n) { - int oldPos = pos; - pos = Math.min(max, pos + (int) n); - return pos - oldPos; - } + private CharsReader(Chars chars) { + this.chars = chars; + this.pos = chars.start; + this.max = chars.start + chars.len; + } - @Override - public void close() { - // nothing to do + @Override + public int read(char @NonNull [] cbuf, int off, int len) throws IOException { + if (len < 0 || off < 0 || off + len > cbuf.length) { + throw new IndexOutOfBoundsException(); } - }; + ensureOpen(); + if (pos >= max) { + return NOT_FOUND; + } + int toRead = Integer.min(max - pos, len); + chars.str.getChars(pos, pos + toRead, cbuf, off); + pos += toRead; + return toRead; + } + + @Override + public int read() throws IOException { + ensureOpen(); + return pos >= max ? NOT_FOUND : chars.str.charAt(pos++); + } + + @Override + public long skip(long n) throws IOException { + ensureOpen(); + int oldPos = pos; + pos = Math.min(max, pos + (int) n); + return pos - oldPos; + } + + private void ensureOpen() throws IOException { + if (chars == null) { + throw new IOException("Closed"); + } + } + + @Override + public void close() { + chars = null; + } + + @Override + public void mark(int readAheadLimit) { + mark = pos; + } + + @Override + public void reset() throws IOException { + ensureOpen(); + if (mark == -1) { + throw new IOException("Reader was not marked"); + } + pos = mark; + } + + @Override + public boolean markSupported() { + return true; + } } } diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlDocument.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlDocument.java index 16527686b8..c9f962a375 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlDocument.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/ASTHtmlDocument.java @@ -13,7 +13,7 @@ import net.sourceforge.pmd.lang.ast.AstInfo; import net.sourceforge.pmd.lang.ast.Parser; import net.sourceforge.pmd.lang.ast.RootNode; -public class ASTHtmlDocument extends ASTHtmlElement implements RootNode { +public final class ASTHtmlDocument extends ASTHtmlElement implements RootNode { private final AstInfo astInfo; diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/AbstractHtmlNode.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/AbstractHtmlNode.java index 288c80c2cd..bd45efd915 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/AbstractHtmlNode.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/AbstractHtmlNode.java @@ -8,11 +8,14 @@ package net.sourceforge.pmd.lang.html.ast; import org.jsoup.nodes.Node; import net.sourceforge.pmd.lang.ast.AstVisitor; -import net.sourceforge.pmd.lang.ast.impl.AbstractNodeWithTextCoordinates; +import net.sourceforge.pmd.lang.ast.impl.AbstractNode; +import net.sourceforge.pmd.lang.document.TextRegion; -abstract class AbstractHtmlNode extends AbstractNodeWithTextCoordinates, HtmlNode> implements HtmlNode { +abstract class AbstractHtmlNode extends AbstractNode, HtmlNode> implements HtmlNode { protected final T node; + protected int startOffset; + protected int endOffset; AbstractHtmlNode(T node) { this.node = node; @@ -27,6 +30,11 @@ abstract class AbstractHtmlNode extends AbstractNodeWithTextCoor return node.nodeName(); } + @Override + public TextRegion getTextRegion() { + return TextRegion.fromBothOffsets(startOffset, endOffset); + } + @Override @SuppressWarnings("unchecked") public final R acceptVisitor(AstVisitor visitor, P data) { @@ -44,8 +52,4 @@ abstract class AbstractHtmlNode extends AbstractNodeWithTextCoor super.addChild(child, index); } - @Override - protected void setCoords(int bline, int bcol, int eline, int ecol) { - super.setCoords(bline, bcol, eline, ecol); - } } diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlParser.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlParser.java index a2ce2533b0..db3d09d393 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlParser.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlParser.java @@ -14,9 +14,8 @@ public final class HtmlParser implements net.sourceforge.pmd.lang.ast.Parser { @Override public ASTHtmlDocument parse(ParserTask task) { - String data = task.getSourceText(); - Document doc = Parser.xmlParser().parseInput(data, ""); + Document doc = Parser.xmlParser().parseInput(task.getTextDocument().getText().newReader(), ""); HtmlTreeBuilder builder = new HtmlTreeBuilder(); - return builder.build(doc, data, task, new HashMap<>()); + return builder.build(doc, task, new HashMap<>()); } } diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlTokenizer.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlTokenizer.java index f99793cb55..55cb84f311 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlTokenizer.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlTokenizer.java @@ -4,35 +4,37 @@ package net.sourceforge.pmd.lang.html.ast; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import java.io.IOException; +import java.io.UncheckedIOException; import net.sourceforge.pmd.cpd.SourceCode; import net.sourceforge.pmd.cpd.TokenEntry; import net.sourceforge.pmd.cpd.Tokenizer; import net.sourceforge.pmd.cpd.Tokens; -import net.sourceforge.pmd.lang.LanguageRegistry; import net.sourceforge.pmd.lang.ast.Parser.ParserTask; import net.sourceforge.pmd.lang.ast.SemanticErrorReporter; -import net.sourceforge.pmd.lang.html.HtmlLanguageModule; +import net.sourceforge.pmd.lang.document.CpdCompat; +import net.sourceforge.pmd.lang.document.TextDocument; public class HtmlTokenizer implements Tokenizer { - private static final Logger LOG = LoggerFactory.getLogger(HtmlTokenizer.class); @Override public void tokenize(SourceCode sourceCode, Tokens tokenEntries) { - ParserTask task = new ParserTask( - LanguageRegistry.getLanguage(HtmlLanguageModule.NAME).getDefaultVersion(), - sourceCode.getFileName(), - sourceCode.getCodeBuffer().toString(), - SemanticErrorReporter.reportToLogger(LOG) - ); + try (TextDocument textDoc = TextDocument.create(CpdCompat.cpdCompat(sourceCode))) { + ParserTask task = new ParserTask( + textDoc, + SemanticErrorReporter.noop()// fixme + ); - HtmlParser parser = new HtmlParser(); - ASTHtmlDocument root = parser.parse(task); + HtmlParser parser = new HtmlParser(); + ASTHtmlDocument root = parser.parse(task); - traverse(root, tokenEntries); - tokenEntries.add(TokenEntry.EOF); + traverse(root, tokenEntries); + } catch (IOException e) { + throw new UncheckedIOException(e); + } finally { + tokenEntries.add(TokenEntry.EOF); + } } private void traverse(HtmlNode node, Tokens tokenEntries) { @@ -42,8 +44,7 @@ public class HtmlTokenizer implements Tokenizer { image = ((ASTHtmlTextNode) node).getText(); } - TokenEntry token = new TokenEntry(image, node.getXPathNodeName(), node.getBeginLine(), - node.getBeginColumn(), node.getEndColumn()); + TokenEntry token = new TokenEntry(image, node.getReportLocation()); tokenEntries.add(token); for (HtmlNode child : node.children()) { diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlTreeBuilder.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlTreeBuilder.java index 44d0996fdc..cc927ddf79 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlTreeBuilder.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/HtmlTreeBuilder.java @@ -20,11 +20,13 @@ import net.sourceforge.pmd.lang.ast.Parser; final class HtmlTreeBuilder { - public ASTHtmlDocument build(Document doc, String htmlString, Parser.ParserTask task, Map suppressMap) { + public ASTHtmlDocument build(Document doc, + Parser.ParserTask task, + Map suppressMap) { ASTHtmlDocument root = new ASTHtmlDocument(doc, task, suppressMap); addChildren(root, doc); - LineNumbers lineNumbers = new LineNumbers(root, htmlString); + LineNumbers lineNumbers = new LineNumbers(root); lineNumbers.determine(); return root; diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/LineNumbers.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/LineNumbers.java index 6ee33e7c8e..d7ae63af8b 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/LineNumbers.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/LineNumbers.java @@ -4,17 +4,16 @@ package net.sourceforge.pmd.lang.html.ast; -import net.sourceforge.pmd.lang.ast.SourceCodePositioner; + +import net.sourceforge.pmd.lang.document.Chars; class LineNumbers { private final ASTHtmlDocument document; - private String htmlString; - private SourceCodePositioner sourceCodePositioner; + private final Chars htmlString; - LineNumbers(ASTHtmlDocument document, String htmlString) { + LineNumbers(ASTHtmlDocument document) { this.document = document; - this.htmlString = htmlString; - this.sourceCodePositioner = new SourceCodePositioner(htmlString); + this.htmlString = document.getTextDocument().getText(); } public void determine() { @@ -80,17 +79,13 @@ class LineNumbers { private void setBeginLocation(AbstractHtmlNode n, int index) { if (n != null) { - int line = sourceCodePositioner.lineNumberFromOffset(index); - int column = sourceCodePositioner.columnFromOffset(line, index); - n.setCoords(line, column, line, column); + n.startOffset = index; } } private void setEndLocation(AbstractHtmlNode n, int index) { if (n != null) { - int line = sourceCodePositioner.lineNumberFromOffset(index); - int column = sourceCodePositioner.columnFromOffset(line, index); - n.setCoords(n.getBeginLine(), n.getBeginColumn(), line, column); + n.endOffset = index; } } } diff --git a/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/HtmlJavaRuleTest.java b/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/HtmlJavaRuleTest.java index 6f0acc19b9..dc3a69cadf 100644 --- a/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/HtmlJavaRuleTest.java +++ b/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/HtmlJavaRuleTest.java @@ -4,21 +4,15 @@ package net.sourceforge.pmd.lang.html; -import java.util.ArrayList; import java.util.List; import org.junit.Assert; import org.junit.Test; +import net.sourceforge.pmd.Report; import net.sourceforge.pmd.Rule; import net.sourceforge.pmd.RuleContext; import net.sourceforge.pmd.RuleViolation; -import net.sourceforge.pmd.lang.LanguageRegistry; -import net.sourceforge.pmd.lang.LanguageVersion; -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.ast.Parser; -import net.sourceforge.pmd.lang.ast.Parser.ParserTask; -import net.sourceforge.pmd.lang.ast.SemanticErrorReporter; import net.sourceforge.pmd.lang.html.ast.ASTHtmlElement; import net.sourceforge.pmd.lang.html.rule.AbstractHtmlRule; import net.sourceforge.pmd.lang.rule.xpath.Attribute; @@ -63,14 +57,7 @@ public class HtmlJavaRuleTest { } private List runRule(String html, Rule rule) { - LanguageVersion htmlLanguage = LanguageRegistry.findLanguageByTerseName(HtmlLanguageModule.TERSE_NAME).getDefaultVersion(); - Parser parser = htmlLanguage.getLanguageVersionHandler().getParser(); - ParserTask parserTask = new ParserTask(htmlLanguage, "n/a", html, SemanticErrorReporter.noop()); - Node node = parser.parse(parserTask); - - List violations = new ArrayList<>(); - RuleContext context = RuleContext.create(violations::add, rule); - rule.apply(node, context); - return violations; + Report report = HtmlParsingHelper.DEFAULT.executeRule(rule, html); + return report.getViolations(); } } diff --git a/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/HtmlParsingHelper.java b/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/HtmlParsingHelper.java new file mode 100644 index 0000000000..7b55840446 --- /dev/null +++ b/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/HtmlParsingHelper.java @@ -0,0 +1,24 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.html; + +import org.checkerframework.checker.nullness.qual.NonNull; + +import net.sourceforge.pmd.lang.ast.test.BaseParsingHelper; +import net.sourceforge.pmd.lang.html.ast.ASTHtmlDocument; + +public class HtmlParsingHelper extends BaseParsingHelper { + + public static final HtmlParsingHelper DEFAULT = new HtmlParsingHelper(Params.getDefault()); + + public HtmlParsingHelper(BaseParsingHelper.Params params) { + super(HtmlLanguageModule.NAME, ASTHtmlDocument.class, params); + } + + @Override + protected @NonNull HtmlParsingHelper clone(@NonNull Params params) { + return new HtmlParsingHelper(params); + } +} diff --git a/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/HtmlXPathRuleTest.java b/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/HtmlXPathRuleTest.java index f6dca7ab97..f54640b6b3 100644 --- a/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/HtmlXPathRuleTest.java +++ b/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/HtmlXPathRuleTest.java @@ -4,35 +4,29 @@ package net.sourceforge.pmd.lang.html; -import java.util.ArrayList; import java.util.List; import org.junit.Assert; import org.junit.Test; -import net.sourceforge.pmd.RuleContext; +import net.sourceforge.pmd.Report; import net.sourceforge.pmd.RuleViolation; -import net.sourceforge.pmd.lang.LanguageRegistry; -import net.sourceforge.pmd.lang.LanguageVersion; -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.ast.Parser; -import net.sourceforge.pmd.lang.ast.Parser.ParserTask; -import net.sourceforge.pmd.lang.ast.SemanticErrorReporter; import net.sourceforge.pmd.lang.rule.XPathRule; import net.sourceforge.pmd.lang.rule.xpath.XPathVersion; public class HtmlXPathRuleTest { + // from https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.js_props_getter private static final String LIGHTNING_WEB_COMPONENT = "\n" - + ""; + + ""; @Test public void selectTextNode() { @@ -57,17 +51,10 @@ public class HtmlXPathRuleTest { } private List runXPath(String html, String xpath) { - LanguageVersion htmlLanguage = LanguageRegistry.findLanguageByTerseName(HtmlLanguageModule.TERSE_NAME).getDefaultVersion(); - Parser parser = htmlLanguage.getLanguageVersionHandler().getParser(); - ParserTask parserTask = new ParserTask(htmlLanguage, "n/a", html, SemanticErrorReporter.noop()); - Node node = parser.parse(parserTask); - - List violations = new ArrayList<>(); XPathRule rule = new XPathRule(XPathVersion.DEFAULT, xpath); rule.setMessage("test"); - rule.setLanguage(htmlLanguage.getLanguage()); - RuleContext context = RuleContext.create(violations::add, rule); - rule.apply(node, context); - return violations; + rule.setLanguage(HtmlParsingHelper.DEFAULT.getLanguage()); + Report report = HtmlParsingHelper.DEFAULT.executeRule(rule, html); + return report.getViolations(); } } From 94f90ffbbf5fd540c2f7fb34ca82e4bd7c267e0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sat, 30 Apr 2022 14:54:22 +0200 Subject: [PATCH 170/180] Add tests for Chars#newReader --- .../pmd/lang/document/CharsTest.java | 157 ++++++++++++++++++ 1 file changed, 157 insertions(+) diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/CharsTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/CharsTest.java index e19a5a5366..9fd02c3620 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/CharsTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/CharsTest.java @@ -14,6 +14,7 @@ import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import java.io.IOException; +import java.io.Reader; import java.io.StringWriter; import java.util.List; import java.util.stream.Collectors; @@ -323,4 +324,160 @@ public class CharsTest { assertEquals(Chars.wrap(expected), actual); } + + @Test + public void testReaderSingleChars() throws IOException { + Chars bc = Chars.wrap("a \n \r\nbc db").slice(1, 9); + // ------------ + + try (Reader reader = bc.newReader()) { + assertEquals(' ', reader.read()); + assertEquals('\n', reader.read()); + assertEquals(' ', reader.read()); + assertEquals(' ', reader.read()); + assertEquals('\r', reader.read()); + assertEquals('\n', reader.read()); + assertEquals('b', reader.read()); + assertEquals('c', reader.read()); + assertEquals(' ', reader.read()); + assertEquals(-1, reader.read()); + } + } + + @Test + public void testReaderBuffer() throws IOException { + Chars bc = Chars.wrap("a \n \r\nbc db").slice(1, 9); + // ------------ + + char[] cbuf = new char[4]; + + try (Reader reader = bc.newReader()) { + assertEquals(4, reader.read(cbuf)); + assertCharBufEquals(" \n ", cbuf); + assertEquals(4, reader.read(cbuf)); + assertCharBufEquals("\r\nbc", cbuf); + assertEquals(1, reader.read(cbuf)); + assertCharBufEquals(" \nbc", cbuf); + assertEquals(-1, reader.read(cbuf)); + } + } + + @Test + public void testReaderSlicedBuffer() throws IOException { + Chars bc = Chars.wrap("a \n \r\nbc db").slice(1, 9); + // ------------ + + // use \0 as padding before and after + char[] cbuf = new char[6]; + + try (Reader reader = bc.newReader()) { + assertEquals(4, reader.read(cbuf, 1, 4)); + assertCharBufEquals("\0 \n \0", cbuf); + assertEquals(5, reader.read(cbuf, 1, 5)); + assertCharBufEquals("\0\r\nbc ", cbuf); + assertEquals(-1, reader.read(cbuf)); + assertEquals(-1, reader.read()); + assertEquals(-1, reader.read(cbuf, 1, 4)); + } + } + + @Test + public void testReadClosed() throws IOException { + Chars bc = Chars.wrap("a \n \r\nbc db").slice(1, 9); + // ------------ + + Reader reader = bc.newReader(); + reader.close(); + assertThrows(IOException.class, reader::read); + } + + @Test + public void testReaderMark() throws IOException { + Chars bc = Chars.wrap("abcdefghijklmnop").slice(1, 9); + // ------------ + + try (Reader reader = bc.newReader()) { + assertTrue("markSupported", reader.markSupported()); + + assertEquals('b', reader.read()); + assertEquals('c', reader.read()); + assertEquals('d', reader.read()); + assertEquals('e', reader.read()); + + reader.mark(10); + + assertEquals('f', reader.read()); + assertEquals('g', reader.read()); + + reader.reset(); + + assertEquals('f', reader.read()); + assertEquals('g', reader.read()); + + reader.reset(); // reset doesn't clear the mark + + assertEquals('f', reader.read()); + assertEquals('g', reader.read()); + } + } + + @Test + public void testReaderMissingMark() throws IOException { + Chars bc = Chars.wrap("abcdefghijklmnop").slice(1, 9); + // ------------ + + try (Reader reader = bc.newReader()) { + assertTrue("markSupported", reader.markSupported()); + + assertEquals('b', reader.read()); + assertThrows(IOException.class, reader::reset); + } + } + + @Test + public void testReaderSkip() throws IOException { + Chars bc = Chars.wrap("abcdefghijklmnop").slice(1, 9); + // ------------ + + try (Reader reader = bc.newReader()) { + assertEquals('b', reader.read()); + assertEquals('c', reader.read()); + assertEquals('d', reader.read()); + assertEquals('e', reader.read()); + + reader.mark(10); + assertEquals(2, reader.skip(2)); + + assertEquals('h', reader.read()); + assertEquals('i', reader.read()); + + reader.reset(); + + assertEquals('f', reader.read()); + assertEquals('g', reader.read()); + } + } + + @Test + public void testReaderInvalidParams() throws IOException { + Chars bc = Chars.wrap("abcdefghijklmnop").slice(1, 9); + // ------------ + char[] cbuf = new char[4]; + + try (Reader reader = bc.newReader()) { + assertTrue("markSupported", reader.markSupported()); + + assertEquals('b', reader.read()); + assertThrows(NullPointerException.class, () -> reader.read(null, 0, 0)); + assertThrows(IndexOutOfBoundsException.class, () -> reader.read(cbuf, -1, 0)); + assertThrows(IndexOutOfBoundsException.class, () -> reader.read(cbuf, 1, 12)); + assertThrows(IndexOutOfBoundsException.class, () -> reader.read(cbuf, 1, -1)); + } + } + + private static void assertCharBufEquals(String expected, char[] cbuf) { + String actual = new String(cbuf); + assertEquals(expected, actual); + } + } From ec4a638d44bee6344aad62c9dd6b398215d9e86a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sat, 30 Apr 2022 15:01:16 +0200 Subject: [PATCH 171/180] Clarify one test --- .../main/java/net/sourceforge/pmd/lang/document/Chars.java | 3 ++- .../sourceforge/pmd/lang/document/TextFileContentTest.java | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java index a2318f5876..32834826c2 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java @@ -506,7 +506,8 @@ public final class Chars implements CharSequence { return h; } - private boolean isFullString() { + // test only + boolean isFullString() { return start == 0 && len == str.length(); } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextFileContentTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextFileContentTest.java index 05dd38fed9..136a9f4f5f 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextFileContentTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextFileContentTest.java @@ -60,8 +60,10 @@ public class TextFileContentTest { TextFileContent content = origin.normalize("\ufeffabc"); Chars normalizedText = content.getNormalizedText(); Assert.assertEquals(Chars.wrap("abc"), normalizedText); - // this means the underlying string does not start with the bom marker - // it's useful for performance to have `textDocument.getText().toString()` be O(1). + // This means the string underlying the Chars does not start with the bom marker. + // It's useful for performance to have `textDocument.getText().toString()` be O(1), + // and not create a new string. + Assert.assertTrue("should be full string", normalizedText.isFullString()); Assert.assertSame(normalizedText.toString(), normalizedText.toString()); } From 17948d1cb8436e48acf5654928cb91ec22daa2ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sat, 30 Apr 2022 15:05:48 +0200 Subject: [PATCH 172/180] Fix some comments --- .../java/net/sourceforge/pmd/lang/apex/ast/ApexParserTest.java | 2 -- pmd-core/src/main/java/net/sourceforge/pmd/cpd/TokenEntry.java | 2 -- .../java/net/sourceforge/pmd/lang/java/metrics/JavaMetrics.java | 1 - 3 files changed, 5 deletions(-) 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 a92c78b4e6..c2623f7f6c 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 @@ -226,9 +226,7 @@ public class ApexParserTest extends ApexParserTestBase { private int visitPosition(Node node, int count) { int result = count + 1; FileLocation loc = node.getReportLocation(); - // todo rename to getStartLine Assert.assertTrue(loc.getStartLine() > 0); - // todo rename to getStartLine Assert.assertTrue(loc.getStartColumn() > 0); Assert.assertTrue(loc.getEndLine() > 0); Assert.assertTrue(loc.getEndColumn() > 0); diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/TokenEntry.java b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/TokenEntry.java index 1fe15d8e5d..2d5ad99b4a 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/TokenEntry.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/TokenEntry.java @@ -78,8 +78,6 @@ public class TokenEntry implements Comparable { } public TokenEntry(String image, FileLocation location) { - // todo rename to getStartLine - // todo rename to getStartLine this(image, location.getFileName(), location.getStartLine(), location.getStartColumn(), location.getEndColumn()); } 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 59c9d66de6..aa8ecb78be 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 @@ -451,7 +451,6 @@ public final class JavaMetrics { // the report location is now not necessarily the entire node. FileLocation loc = node.getTextDocument().toLocation(node.getTextRegion()); - // todo rename to getStartLine return 1 + loc.getEndLine() - loc.getStartLine(); } From 7c536288e894e6a9e07c3473ab743893879a2124 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sat, 30 Apr 2022 15:27:17 +0200 Subject: [PATCH 173/180] Cleanup apex tests --- .../pmd/lang/apex/ast/ApexParserTest.java | 52 +++++++++++-------- .../pmd/lang/document/NioTextFile.java | 4 +- .../pmd/lang/ast/test/NodeExtensions.kt | 2 +- .../pmd/lang/ast/test/TestUtils.kt | 19 +++++-- 4 files changed, 47 insertions(+), 30 deletions(-) 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 c2623f7f6c..ae6b37127d 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 @@ -4,10 +4,12 @@ package net.sourceforge.pmd.lang.apex.ast; +import static net.sourceforge.pmd.lang.ast.test.NodeExtensionsKt.textOfReportLocation; import static net.sourceforge.pmd.lang.ast.test.TestUtilsKt.assertPosition; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.IsInstanceOf.instanceOf; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.io.File; @@ -18,7 +20,6 @@ import java.util.List; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.junit.Assert; -import org.junit.Ignore; import org.junit.Test; import net.sourceforge.pmd.lang.ast.Node; @@ -75,22 +76,22 @@ public class ApexParserTest extends ApexParserTestBase { assertLineNumbersForTestCode(rootNode); } - private void assertLineNumbersForTestCode(ASTUserClassOrInterface rootNode) { + private void assertLineNumbersForTestCode(ASTUserClassOrInterface classNode) { // whole source code, well from the beginning of the class // name Modifier of the class - doesn't work. This node just // sees the identifier ("SimpleClass") // assertPosition(rootNode.getChild(0), 1, 1, 1, 6); - // "public" - assertPosition(rootNode, 1, 14, 1, 25); + // identifier: "SimpleClass" + assertPosition(classNode, 1, 14, 1, 25); + assertTextEquals("SimpleClass", classNode); - // "method1" - starts with identifier until end of its block statement - Node method1 = rootNode.getChild(1); + // identifier: "method1" + Node method1 = classNode.getChild(1); + assertTextEquals("method1", method1); assertPosition(method1, 2, 17, 2, 24); - // Modifier of method1 - doesn't work. This node just sees the - // identifier ("method1") - // assertPosition(method1.getChild(0), 2, 17, 2, 20); // "public" for - // method1 + // modifiers have same location + assertPosition(method1.getChild(0), 2, 17, 2, 24); // BlockStatement - the whole method body Node blockStatement = method1.getChild(1); @@ -100,6 +101,7 @@ public class ApexParserTest extends ApexParserTestBase { // the expression ("System.out...") Node expressionStatement = blockStatement.getChild(0); assertPosition(expressionStatement, 3, 20, 3, 35); + assertTextEquals("println('abc');", expressionStatement); } @Test @@ -189,36 +191,36 @@ public class ApexParserTest extends ApexParserTestBase { } @Test - @Ignore("This is buggy, I'd like to stop pretending our reportLocation is a real node position") - public void verifyLineColumnNumbersInnerClasses() throws Exception { + public void verifyLineColumnNumbersInnerClasses() { ASTApexFile rootNode = apex.parseResource("InnerClassLocations.cls"); Assert.assertNotNull(rootNode); visitPosition(rootNode, 0); - Assert.assertEquals("InnerClassLocations", rootNode.getMainNode().getSimpleName()); + ASTUserClassOrInterface classNode = rootNode.getMainNode(); + Assert.assertEquals("InnerClassLocations", classNode.getSimpleName()); + assertTextEquals("InnerClassLocations", classNode); // Note: Apex parser doesn't provide positions for "public class" keywords. The // position of the UserClass node is just the identifier. So, the node starts // with the identifier and not with the first keyword in the file... - assertPosition(rootNode, 1, 14, 16, 2); + assertPosition(classNode, 1, 14, 1, 33); - List classes = rootNode.descendants(ASTUserClass.class).toList(); + List classes = classNode.descendants(ASTUserClass.class).toList(); Assert.assertEquals(2, classes.size()); Assert.assertEquals("bar1", classes.get(0).getSimpleName()); List methods = classes.get(0).children(ASTMethod.class).toList(); Assert.assertEquals(2, methods.size()); // m() and synthetic clone() Assert.assertEquals("m", methods.get(0).getImage()); - assertPosition(methods.get(0), 4, 21, 7, 9); + assertPosition(methods.get(0), 4, 21, 4, 22); Assert.assertEquals("clone", methods.get(1).getImage()); - assertPosition(methods.get(1), 7, 9, 7, 9); + assertFalse(methods.get(1).hasRealLoc()); + assertPosition(methods.get(1), 3, 18, 3, 22); - // Position of the first inner class: starts with the identifier "bar1" and ends with - // the last real method m(). The last bracket it actually on the next line 8, but we - // don't see this in the AST. - assertPosition(classes.get(0), 3, 18, 7, 9); + // Position of the first inner class is its identifier + assertPosition(classes.get(0), 3, 18, 3, 22); - Assert.assertEquals("bar2", classes.get(1).getImage()); - assertPosition(classes.get(1), 10, 18, 14, 9); + Assert.assertEquals("bar2", classes.get(1).getSimpleName()); + assertPosition(classes.get(1), 10, 18, 10, 22); } // TEST HELPER @@ -235,4 +237,8 @@ public class ApexParserTest extends ApexParserTestBase { } return result; } + + private void assertTextEquals(String expected, Node expressionStatement) { + assertEquals(expected, textOfReportLocation(expressionStatement)); + } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/NioTextFile.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/NioTextFile.java index c0400e9294..95e7086818 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/NioTextFile.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/NioTextFile.java @@ -27,6 +27,7 @@ class NioTextFile extends BaseCloseable implements TextFile { private final Charset charset; private final LanguageVersion languageVersion; private final @Nullable String displayName; + private final String pathId; private boolean readOnly; NioTextFile(Path path, @@ -43,6 +44,7 @@ class NioTextFile extends BaseCloseable implements TextFile { this.path = path; this.charset = charset; this.languageVersion = languageVersion; + this.pathId = path.toAbsolutePath().toString(); } @Override @@ -57,7 +59,7 @@ class NioTextFile extends BaseCloseable implements TextFile { @Override public String getPathId() { - return path.toAbsolutePath().toString(); + return pathId; } @Override diff --git a/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/NodeExtensions.kt b/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/NodeExtensions.kt index 6a1ba946b2..a0a0ac071e 100644 --- a/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/NodeExtensions.kt +++ b/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/NodeExtensions.kt @@ -23,7 +23,7 @@ infix fun TextAvailableNode.shouldHaveText(str: String) { inline fun Node.getDescendantsOfType(): List = descendants(T::class.java).toList() inline fun Node.getFirstDescendantOfType(): T = descendants(T::class.java).firstOrThrow() -fun TextAvailableNode.textOfReportLocation(): String? = +fun Node.textOfReportLocation(): String? = reportLocation.regionInFile?.let(textDocument::sliceText)?.toString() diff --git a/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/TestUtils.kt b/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/TestUtils.kt index d43e2b1f14..5819192522 100644 --- a/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/TestUtils.kt +++ b/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/TestUtils.kt @@ -4,6 +4,7 @@ package net.sourceforge.pmd.lang.ast.test +import io.kotest.assertions.withClue import io.kotest.matchers.Matcher import io.kotest.matchers.equalityMatcher import io.kotest.matchers.should @@ -94,13 +95,21 @@ fun assertSuppressed(report: Report, size: Int): List Date: Sat, 30 Apr 2022 15:36:42 +0200 Subject: [PATCH 174/180] Update plsql references --- .../net/sourceforge/pmd/lang/plsql/ast/ParsingExclusion.txt | 2 +- .../net/sourceforge/pmd/lang/plsql/ast/SelectIntoArray.txt | 2 +- .../pmd/lang/plsql/ast/SqlPlusLexicalVariablesIssue195.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParsingExclusion.txt b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParsingExclusion.txt index 608a8241ac..7022ea8e0a 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParsingExclusion.txt +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParsingExclusion.txt @@ -1,4 +1,4 @@ -+- Input[@CanonicalImage = null, @ExcludedLinesCount = "6", @ExcludedRangesCount = "2"] ++- Input[@CanonicalImage = null, @ExcludedLinesCount = 6, @ExcludedRangesCount = 2] +- Global[@CanonicalImage = null] | +- Block[@CanonicalImage = null] | +- Statement[@CanonicalImage = null] diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/SelectIntoArray.txt b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/SelectIntoArray.txt index 0d163bdd0d..78b8418f5b 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/SelectIntoArray.txt +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/SelectIntoArray.txt @@ -1,4 +1,4 @@ -+- Input[@CanonicalImage = null, @ExcludedLinesCount = "0", @ExcludedRangesCount = "0"] ++- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0] +- Global[@CanonicalImage = null] +- ProgramUnit[@CanonicalImage = null, @MethodName = "EXAMPLE_PROCEDURE", @Name = "EXAMPLE_PROCEDURE", @ObjectName = null] +- MethodDeclarator[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE", @ParameterCount = 1] diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/SqlPlusLexicalVariablesIssue195.txt b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/SqlPlusLexicalVariablesIssue195.txt index efec9a5183..b549a06aef 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/SqlPlusLexicalVariablesIssue195.txt +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/SqlPlusLexicalVariablesIssue195.txt @@ -1,3 +1,3 @@ -+- Input[@CanonicalImage = null, @ExcludedLinesCount = "0", @ExcludedRangesCount = "0"] ++- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0] +- SqlPlusCommand[@CanonicalImage = "DEFINE PATCH_NAME = ACME_MODULE", @Image = "define patch_name = acme_module "] +- SqlPlusCommand[@CanonicalImage = "SPOOL &PATCH_NAME. . LOG", @Image = "spool &patch_name. . log "] From 515df821d8b78ac184666f88c471f1a31f86b8f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sat, 30 Apr 2022 15:39:06 +0200 Subject: [PATCH 175/180] doc --- .../net/sourceforge/pmd/lang/document/SourceCodePositioner.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/SourceCodePositioner.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/SourceCodePositioner.java index 424f8db48f..cf8caab34c 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/SourceCodePositioner.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/SourceCodePositioner.java @@ -184,6 +184,8 @@ final class SourceCodePositioner { /** * Builds a new positioner for the given char sequence. + * The char sequence should have its newline delimiters normalized + * to {@link TextFileContent#NORMALIZED_LINE_TERM}. * The char sequence should not change state (eg a {@link StringBuilder}) * after construction, otherwise this positioner becomes unreliable. * From d1d2f3011911497a11d6aec5733c6d79e9f51fee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sat, 30 Apr 2022 15:50:40 +0200 Subject: [PATCH 176/180] Remove some things from TextDocument --- .../ast/impl/javacc/JavaccTokenDocument.java | 2 + .../pmd/lang/document/BaseMappedDocument.java | 14 +--- .../lang/document/FragmentedTextDocument.java | 45 ++-------- .../pmd/lang/document/TextDocument.java | 82 ------------------- .../pmd/lang/document/TextPos2d.java | 5 -- .../pmd/lang/document/TextDocumentTest.java | 2 +- pmd-java/etc/grammar/Java.jjt | 4 +- .../sourceforge/pmd/cpd/JavaTokenizer.java | 3 +- pmd-plsql/etc/grammar/PLSQL.jjt | 1 + .../pmd/cpd/ScalaTokenAdapter.java | 2 +- 10 files changed, 17 insertions(+), 143 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/javacc/JavaccTokenDocument.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/javacc/JavaccTokenDocument.java index 3538b6d4ff..3dca87e381 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/javacc/JavaccTokenDocument.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/javacc/JavaccTokenDocument.java @@ -57,6 +57,8 @@ public final class JavaccTokenDocument extends TokenDocument { * @param text Source doc * * @see EscapeTranslator + * + * TODO move that to LanguageVersionHandler once #3919 (Merge CPD and PMD language) is implemented */ protected TextDocument translate(TextDocument text) throws MalformedSourceException { return text; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/BaseMappedDocument.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/BaseMappedDocument.java index cbea8633d8..399f42f737 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/BaseMappedDocument.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/BaseMappedDocument.java @@ -59,19 +59,9 @@ abstract class BaseMappedDocument implements TextDocument { return base.createLineRange(startLineInclusive, endLineInclusive); } - @Override - public int offsetAtLineColumn(int line, int column) { - throw new UnsupportedOperationException(); - } - @Override public TextPos2d lineColumnAtOffset(int offset, boolean inclusive) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean isInRange(TextPos2d textPos2d) { - return false; + return base.lineColumnAtOffset(localOffsetTransform(offset, inclusive)); } @Override @@ -87,8 +77,6 @@ abstract class BaseMappedDocument implements TextDocument { */ protected abstract int localOffsetTransform(int outOffset, boolean inclusive); - protected abstract int inverseLocalOffsetTransform(int inOffset, boolean inclusive); - @Override public void close() throws IOException { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/FragmentedTextDocument.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/FragmentedTextDocument.java index 99be79f6df..c3f372892a 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/FragmentedTextDocument.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/FragmentedTextDocument.java @@ -4,8 +4,6 @@ package net.sourceforge.pmd.lang.document; -import java.util.function.ToIntFunction; - import org.checkerframework.checker.nullness.qual.Nullable; import net.sourceforge.pmd.lang.LanguageVersion; @@ -47,74 +45,47 @@ final class FragmentedTextDocument extends BaseMappedDocument implements TextDoc return base.getLanguageVersion(); } - @Override protected int localOffsetTransform(int outOffset, boolean inclusive) { - return offsetTransform(outOffset, inclusive, - Fragment::outToIn, - Fragment::outEnd, - Fragment::outStart - ); - } - - @Override - protected int inverseLocalOffsetTransform(int inOffset, boolean inclusive) { - return offsetTransform(inOffset, inclusive, - Fragment::inToOut, - Fragment::inEnd, - Fragment::inStart - ); - } - - interface OffsetMapper { - - int mapOffset(Fragment fragment, int offset); - } - - private int offsetTransform(int offset, - boolean inclusive, - OffsetMapper mapOffsetWhenContains, - ToIntFunction end, - ToIntFunction start) { // caching the last accessed fragment instead of doing // a linear search is critical for performance. Fragment f = this.lastAccessedFragment; if (f == null) { - return offset; + return outOffset; } // Whether the fragment contains the offset we're looking for. // Will be true most of the time. boolean containsOffset = - start.applyAsInt(f) >= offset && offset < end.applyAsInt(f); + f.outStart() >= outOffset && outOffset < f.outEnd(); if (!containsOffset) { // Slow path, we must search for the fragment // This optimisation is important, otherwise we have // to search for very long times in some files - if (end.applyAsInt(f) < offset) { // search forward - while (f.next != null && end.applyAsInt(f) < offset) { + if (f.outEnd() < outOffset) { // search forward + while (f.next != null && f.outEnd() < outOffset) { f = f.next; } } else { // search backwards - while (f.prev != null && offset <= start.applyAsInt(f)) { + while (f.prev != null && outOffset <= f.outStart()) { f = f.prev; } } lastAccessedFragment = f; } - if (!inclusive && end.applyAsInt(f) == offset) { + if (!inclusive && f.outEnd() == outOffset) { if (f.next != null) { f = f.next; lastAccessedFragment = f; // fallthrough } else { - return mapOffsetWhenContains.mapOffset(f, offset) + 1; + return f.outToIn(outOffset) + 1; } } - return mapOffsetWhenContains.mapOffset(f, offset); + return f.outToIn(outOffset); } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextDocument.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextDocument.java index b2fe186cff..5003ed6a70 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextDocument.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextDocument.java @@ -180,21 +180,6 @@ public interface TextDocument extends Closeable { */ TextRegion inputRegion(TextRegion outputRegion); - /** - * Translate a 2D range given in the coordinate system of this - * document, to the coordinate system of the original document. - * This works as if creating a new region with both start and end - * offsets translated through {@link #inputOffset(int, boolean)}. The - * returned region may have a different length. - * - * @param outputRange Output region - * - * @return Input region - */ - default TextRange2d inputRange(TextRange2d outputRange) { - return toRange2d(inputRegion(toRegion(outputRange))); - } - /** * Returns a reader over the text of this document. @@ -218,14 +203,6 @@ public interface TextDocument extends Closeable { return TextRegion.fromOffsetLength(0, getLength()); } - /** - * Returns a 2D text range that corresponds to the entire document, - * in the coordinate system of this document. - */ - default TextRange2d getEntireRegion2d() { - return toRange2d(getEntireRegion()); - } - /** * Returns a region that spans the text of all the given lines. * This is intended to provide a replacement for {@link SourceCode#getSlice(int, int)}. @@ -257,65 +234,6 @@ public interface TextDocument extends Closeable { */ FileLocation toLocation(TextRegion region); - /** - * Turn a text region into a {@link FileLocation}. The file name is - * the display name of this document. - * - * @return A new file position - * - * @throws IndexOutOfBoundsException If the argument is not a valid region in this document - */ - default FileLocation toLocation(TextRange2d range) { - int startOffset = offsetAtLineColumn(range.getStartPos()); - if (startOffset < 0) { - throw new IndexOutOfBoundsException("Region out of bounds: " + range.displayString()); - } - TextRegion region = TextRegion.caretAt(startOffset); - checkInRange(region, this.getLength()); - return FileLocation.range(getDisplayName(), range); - } - - /** - * Turn a text region to a {@link TextRange2d}. - */ - default TextRange2d toRange2d(TextRegion region) { - TextPos2d start = lineColumnAtOffset(region.getStartOffset(), true); - TextPos2d end = lineColumnAtOffset(region.getEndOffset(), false); - return TextRange2d.range2d(start, end); - } - - /** - * Turn a {@link TextRange2d} into a {@link TextRegion}. - */ - default TextRegion toRegion(TextRange2d region) { - return TextRegion.fromBothOffsets( - offsetAtLineColumn(region.getStartPos()), - offsetAtLineColumn(region.getEndPos()) - ); - } - - - /** - * Returns the offset at the given line and column number. - * - * @param line Line number (1-based) - * @param column Column number (1-based) - * - * @return an offset (0-based) - */ - int offsetAtLineColumn(int line, int column); - - /** - * Returns true if the position is valid in this document. - */ - boolean isInRange(TextPos2d textPos2d); - - /** - * Returns the offset at the line and number. - */ - default int offsetAtLineColumn(TextPos2d pos2d) { - return offsetAtLineColumn(pos2d.getLine(), pos2d.getColumn()); - } /** * Returns the line and column at the given offset (inclusive). diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextPos2d.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextPos2d.java index 3a492f097a..b554cd3eda 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextPos2d.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextPos2d.java @@ -11,11 +11,6 @@ import org.checkerframework.checker.nullness.qual.NonNull; */ public final class TextPos2d implements Comparable { - /** - * The position at the start of the document (line 1, column 1). - */ - public static TextPos2d DOCUMENT_START = new TextPos2d(1, 1); - private final int line; private final int column; diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextDocumentTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextDocumentTest.java index af41bd22e0..0f7d2b9a91 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextDocumentTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextDocumentTest.java @@ -147,7 +147,7 @@ public class TextDocumentTest { } private void assertPos2dEqualsAt(TextDocument doc, int offset, String c, TextPos2d pos, boolean inclusive) { - Chars slicedChar = doc.sliceText(TextRegion.fromOffsetLength(offset, 1)); + Chars slicedChar = doc.sliceTranslatedText(TextRegion.fromOffsetLength(offset, 1)); assertEquals(c, slicedChar.toString()); assertEquals(pos, doc.lineColumnAtOffset(offset, inclusive)); } diff --git a/pmd-java/etc/grammar/Java.jjt b/pmd-java/etc/grammar/Java.jjt index 0ec6e94d12..dc698ede22 100644 --- a/pmd-java/etc/grammar/Java.jjt +++ b/pmd-java/etc/grammar/Java.jjt @@ -2618,14 +2618,14 @@ void AssertStatement() : void RUNSIGNEDSHIFT() #void: {} { - LOOKAHEAD({ JavaTokenDocument.getRealKind(getToken(1)) == RUNSIGNEDSHIFT}) + LOOKAHEAD({ JavaTokenDocumentBehavior.getRealKind(getToken(1)) == RUNSIGNEDSHIFT}) ">" ">" ">" } void RSIGNEDSHIFT() #void: {} { - LOOKAHEAD({ JavaTokenDocument.getRealKind(getToken(1)) == RSIGNEDSHIFT}) + LOOKAHEAD({ JavaTokenDocumentBehavior.getRealKind(getToken(1)) == RSIGNEDSHIFT}) ">" ">" } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/cpd/JavaTokenizer.java b/pmd-java/src/main/java/net/sourceforge/pmd/cpd/JavaTokenizer.java index 172be221fc..525d1731b2 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/cpd/JavaTokenizer.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/cpd/JavaTokenizer.java @@ -15,7 +15,6 @@ import net.sourceforge.pmd.cpd.token.TokenFilter; import net.sourceforge.pmd.lang.TokenManager; import net.sourceforge.pmd.lang.ast.impl.javacc.CharStream; import net.sourceforge.pmd.lang.ast.impl.javacc.JavaccToken; -import net.sourceforge.pmd.lang.document.TextDocument; import net.sourceforge.pmd.lang.ast.impl.javacc.JavaccTokenDocument; import net.sourceforge.pmd.lang.java.ast.InternalApiBridge; import net.sourceforge.pmd.lang.java.ast.JavaTokenKinds; @@ -44,7 +43,7 @@ public class JavaTokenizer extends JavaCCTokenizer { } @Override - protected JavaccTokenDocument.TokenDocumentBehavior tokenBehavior() throws IOException { + protected JavaccTokenDocument.TokenDocumentBehavior tokenBehavior() { return InternalApiBridge.javaTokenDoc(); } diff --git a/pmd-plsql/etc/grammar/PLSQL.jjt b/pmd-plsql/etc/grammar/PLSQL.jjt index 4688c275fc..41fbefea0c 100644 --- a/pmd-plsql/etc/grammar/PLSQL.jjt +++ b/pmd-plsql/etc/grammar/PLSQL.jjt @@ -160,6 +160,7 @@ package net.sourceforge.pmd.lang.plsql.ast; import java.util.List; import java.util.ArrayList; import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.document.Chars; import net.sourceforge.pmd.lang.ast.impl.javacc.CharStream; import net.sourceforge.pmd.lang.plsql.ast.internal.ParsingExclusion; import net.sourceforge.pmd.lang.ast.TokenMgrError; diff --git a/pmd-scala-modules/pmd-scala-common/src/main/java/net/sourceforge/pmd/cpd/ScalaTokenAdapter.java b/pmd-scala-modules/pmd-scala-common/src/main/java/net/sourceforge/pmd/cpd/ScalaTokenAdapter.java index 06853bbe71..3609cd8efb 100644 --- a/pmd-scala-modules/pmd-scala-common/src/main/java/net/sourceforge/pmd/cpd/ScalaTokenAdapter.java +++ b/pmd-scala-modules/pmd-scala-common/src/main/java/net/sourceforge/pmd/cpd/ScalaTokenAdapter.java @@ -44,7 +44,7 @@ public class ScalaTokenAdapter implements GenericToken { @Override public Chars getImageCs() { - return textDocument.sliceText(getRegion()); + return textDocument.sliceTranslatedText(getRegion()); } @Override From d797c861e72cca01fd9dd225aa6288d6b2914675 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sat, 30 Apr 2022 16:09:31 +0200 Subject: [PATCH 177/180] Fix last psql refs --- .../plsql/ast/AllPlsqlAstTreeDumpTest.java | 19 +++++++++++++++++++ .../ast/ExecuteImmediateBulkCollect1.txt | 2 +- .../ast/ExecuteImmediateBulkCollect2.txt | 2 +- .../ast/ExecuteImmediateBulkCollect3.txt | 2 +- .../pmd/lang/plsql/ast/ParenthesisGroup0.txt | 2 +- .../pmd/lang/plsql/ast/ParenthesisGroup1.txt | 2 +- .../pmd/lang/plsql/ast/ParenthesisGroup2.txt | 2 +- 7 files changed, 25 insertions(+), 6 deletions(-) create mode 100644 pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/AllPlsqlAstTreeDumpTest.java diff --git a/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/AllPlsqlAstTreeDumpTest.java b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/AllPlsqlAstTreeDumpTest.java new file mode 100644 index 0000000000..4b09b78897 --- /dev/null +++ b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/AllPlsqlAstTreeDumpTest.java @@ -0,0 +1,19 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.plsql.ast; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +@RunWith(Suite.class) +@SuiteClasses({ + PlsqlTreeDumpTest.class, + ParenthesisGroupTest.class, + ExecuteImmediateBulkCollectTest.class +}) +public class AllPlsqlAstTreeDumpTest { + +} diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect1.txt b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect1.txt index 66c85d1839..1a37b67ae3 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect1.txt +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect1.txt @@ -1,4 +1,4 @@ -+- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0, @Sourcecode = "--\n-- BSD-style license; for more info see http://pmd.sourceforge.net/license.html\n--\n\nCREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS\n --\n TYPE t_data IS TABLE OF dual%ROWTYPE INDEX BY BINARY_INTEGER;\n --\n l_data t_data;\n l_sql VARCHAR2(500);\n --\nBEGIN\n --\n l_sql := \'SELECT * FROM DUAL\';\n --\n EXECUTE IMMEDIATE l_sql BULK COLLECT\n INTO l_data;\n --\nEND EXAMPLE_PROCEDURE;\n"] ++- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0] +- Global[@CanonicalImage = null] +- ProgramUnit[@CanonicalImage = null, @MethodName = "EXAMPLE_PROCEDURE", @Name = "EXAMPLE_PROCEDURE", @ObjectName = null] +- MethodDeclarator[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE", @ParameterCount = 1] diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect2.txt b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect2.txt index 8965dd564c..6864c8b811 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect2.txt +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect2.txt @@ -1,4 +1,4 @@ -+- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0, @Sourcecode = "--\n-- BSD-style license; for more info see http://pmd.sourceforge.net/license.html\n--\n\nCREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS\n --\n TYPE t_data_key IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;\n TYPE t_data_description IS TABLE OF VARCHAR2(100) INDEX BY BINARY_INTEGER;\n --\n l_data_key t_data_key;\n l_data_description t_data_description;\n l_sql VARCHAR2(500);\n p_rownum1 NUMBER(20);\n p_rownum2 NUMBER(20);\n --\nBEGIN\n --\n p_rownum1 := 10;\n p_rownum2 := 30;\n --\n l_sql := \'SELECT 1, \' || CHR(39) || \'First key\' || CHR(39) || \n \' FROM DUAL \'||\' WHERE ROWNUM <= :p_rownum1 \' ||\n \'UNION ALL \'||\n \'SELECT 2, \' || CHR(39) || \'Second key \' || CHR(39) || \n \' FROM DUAL\'||\' WHERE ROWNUM <= :p_rownum2 \';\n --\n EXECUTE IMMEDIATE l_sql BULK COLLECT\n INTO l_data_key, l_data_description USING p_rownum1, p_rownum2;\n --\nEND EXAMPLE_PROCEDURE;\n"] ++- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0] +- Global[@CanonicalImage = null] +- ProgramUnit[@CanonicalImage = null, @MethodName = "EXAMPLE_PROCEDURE", @Name = "EXAMPLE_PROCEDURE", @ObjectName = null] +- MethodDeclarator[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE", @ParameterCount = 1] diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect3.txt b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect3.txt index 14ea63e5da..2d8a3b127a 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect3.txt +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateBulkCollect3.txt @@ -1,4 +1,4 @@ -+- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0, @Sourcecode = "--\n-- BSD-style license; for more info see http://pmd.sourceforge.net/license.html\n--\n\nCREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS\n --\n TYPE t_data_key IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;\n TYPE t_data_description IS TABLE OF VARCHAR2(100) INDEX BY BINARY_INTEGER;\n --\n l_data_key t_data_key;\n l_data_description t_data_description;\n l_sql VARCHAR2(500);\n --\nBEGIN\n --\n l_sql := \'SELECT 1, \' || CHR(39) || \'First key\' || CHR(39) || \n \' FROM DUAL \'||\n \'UNION ALL \'||\n \'SELECT 2, \' || CHR(39) || \'Second key \' || CHR(39) || \n \' FROM DUAL\';\n --\n EXECUTE IMMEDIATE l_sql BULK COLLECT\n INTO l_data_key, l_data_description;\n --\nEND EXAMPLE_PROCEDURE;\n"] ++- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0] +- Global[@CanonicalImage = null] +- ProgramUnit[@CanonicalImage = null, @MethodName = "EXAMPLE_PROCEDURE", @Name = "EXAMPLE_PROCEDURE", @ObjectName = null] +- MethodDeclarator[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE", @ParameterCount = 1] diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup0.txt b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup0.txt index 70ad135b19..c45893721b 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup0.txt +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup0.txt @@ -1,4 +1,4 @@ -+- Input[@CanonicalImage = null, @ExcludedLinesCount = "0", @ExcludedRangesCount = "0"] ++- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0] +- Global[@CanonicalImage = null] +- ProgramUnit[@CanonicalImage = null, @MethodName = "EXAMPLE_PROCEDURE", @Name = "EXAMPLE_PROCEDURE", @ObjectName = null] +- MethodDeclarator[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE", @ParameterCount = 1] diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup1.txt b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup1.txt index 3509d8568b..71d9aa3509 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup1.txt +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup1.txt @@ -1,4 +1,4 @@ -+- Input[@CanonicalImage = null, @ExcludedLinesCount = "0", @ExcludedRangesCount = "0"] ++- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0] +- Global[@CanonicalImage = null] +- ProgramUnit[@CanonicalImage = null, @MethodName = "EXAMPLE_PROCEDURE", @Name = "EXAMPLE_PROCEDURE", @ObjectName = null] +- MethodDeclarator[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE", @ParameterCount = 1] diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup2.txt b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup2.txt index ec719209ce..7880baff0a 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup2.txt +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ParenthesisGroup2.txt @@ -1,4 +1,4 @@ -+- Input[@CanonicalImage = null, @ExcludedLinesCount = "0", @ExcludedRangesCount = "0"] ++- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0] +- Global[@CanonicalImage = null] +- ProgramUnit[@CanonicalImage = null, @MethodName = "TEST_PROCEDURE", @Name = "TEST_PROCEDURE", @ObjectName = null] +- MethodDeclarator[@CanonicalImage = "TEST_PROCEDURE", @Image = "TEST_PROCEDURE", @ParameterCount = 1] From 158f0a6ee3731144d29cb976a34dc099a9c2144c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sat, 30 Apr 2022 16:55:34 +0200 Subject: [PATCH 178/180] Fix bug with string literals --- .../pmd/lang/ast/TextAvailableNode.java | 41 ++++++++++----- .../ast/impl/javacc/AbstractJjtreeNode.java | 6 --- .../pmd/lang/ast/impl/javacc/JjtreeNode.java | 4 -- .../pmd/lang/document/BaseMappedDocument.java | 52 ++++++++++++++----- .../sourceforge/pmd/lang/document/Chars.java | 10 ++++ .../lang/document/FragmentedTextDocument.java | 2 +- .../pmd/lang/document/RootTextDocument.java | 10 ---- .../pmd/lang/document/TextDocument.java | 39 -------------- .../pmd/lang/document/CharsTest.java | 8 +++ .../pmd/lang/java/ast/ASTStringLiteral.java | 10 ++-- .../pmd/lang/java/ast/ASTLiteralTest.kt | 19 ++++++- 11 files changed, 110 insertions(+), 91 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/TextAvailableNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/TextAvailableNode.java index 4d9841cb10..8f400cbfb6 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/TextAvailableNode.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/TextAvailableNode.java @@ -4,6 +4,7 @@ package net.sourceforge.pmd.lang.ast; +import net.sourceforge.pmd.lang.document.Chars; import net.sourceforge.pmd.lang.document.TextDocument; import net.sourceforge.pmd.lang.document.TextRegion; import net.sourceforge.pmd.lang.rule.xpath.NoAttribute; @@ -18,27 +19,39 @@ public interface TextAvailableNode extends Node { /** - * Returns the exact region of text delimiting - * the node in the underlying text document. Note - * that {@link #getReportLocation()} does not need - * to match this region. {@link #getReportLocation()} - * can be scoped down to a specific token, eg the - * class identifier. This region uses the translated - * coordinate system, ie the coordinate system - * of {@link #getTextDocument()}. + * Returns the exact region of text delimiting the node in the underlying + * text document. Note that {@link #getReportLocation()} does not need + * to match this region. {@link #getReportLocation()} can be scoped down + * to a specific token, eg the class identifier. This region uses + * the translated coordinate system, ie the coordinate system of + * {@link #getTextDocument()}. */ @Override TextRegion getTextRegion(); /** - * Returns the original source code underlying this node. In particular, - * for a {@link RootNode}, returns the whole text of the file. Note the - * difference between this method and {@code getTextDocument().getText().slice(getTextRegion())}. - * The latter is {@link TextDocument#sliceTranslatedText(TextRegion)}, - * the former (this method) is {@link TextDocument#sliceOriginalText(TextRegion)}. + * Returns the original source code underlying this node, before + * any escapes have been translated. In particular, for a {@link RootNode}, + * returns the whole text of the file. + * + * @see TextDocument#sliceOriginalText(TextRegion) */ @NoAttribute - CharSequence getText(); + default Chars getOriginalText() { + return getTextDocument().sliceOriginalText(getTextRegion()); + } + + /** + * Returns the source code underlying this node, after any escapes + * have been translated. In particular, for a {@link RootNode}, returns + * the whole text of the file. + * + * @see TextDocument#sliceTranslatedText(TextRegion) + */ + @NoAttribute + default Chars getText() { + return getTextDocument().sliceTranslatedText(getTextRegion()); + } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/javacc/AbstractJjtreeNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/javacc/AbstractJjtreeNode.java index 4097225d96..bd11611c28 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/javacc/AbstractJjtreeNode.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/javacc/AbstractJjtreeNode.java @@ -7,7 +7,6 @@ package net.sourceforge.pmd.lang.ast.impl.javacc; import net.sourceforge.pmd.annotation.Experimental; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.ast.impl.AbstractNode; -import net.sourceforge.pmd.lang.document.Chars; import net.sourceforge.pmd.lang.document.FileLocation; import net.sourceforge.pmd.lang.document.TextRegion; import net.sourceforge.pmd.util.StringUtil; @@ -48,11 +47,6 @@ public abstract class AbstractJjtreeNode, N e this.image = image; } - @Override - public final Chars getText() { - return getTextDocument().sliceOriginalText(getTextRegion()); - } - @Override public final TextRegion getTextRegion() { return TextRegion.fromBothOffsets(getFirstToken().getStartOffset(), diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/javacc/JjtreeNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/javacc/JjtreeNode.java index f7175cd2b3..0af5cfe313 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/javacc/JjtreeNode.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/javacc/JjtreeNode.java @@ -6,7 +6,6 @@ package net.sourceforge.pmd.lang.ast.impl.javacc; import net.sourceforge.pmd.lang.ast.TextAvailableNode; import net.sourceforge.pmd.lang.ast.impl.GenericNode; -import net.sourceforge.pmd.lang.document.Chars; import net.sourceforge.pmd.reporting.Reportable; /** @@ -18,9 +17,6 @@ import net.sourceforge.pmd.reporting.Reportable; */ public interface JjtreeNode> extends GenericNode, TextAvailableNode, Reportable { - @Override - Chars getText(); - // todo token accessors should most likely be protected in PMD 7. diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/BaseMappedDocument.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/BaseMappedDocument.java index 399f42f737..d6e8fc9e8e 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/BaseMappedDocument.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/BaseMappedDocument.java @@ -45,14 +45,6 @@ abstract class BaseMappedDocument implements TextDocument { return base.toLocation(inputRegion(region)); } - @Override - public @NonNull TextRegion inputRegion(TextRegion outputRegion) { - // note that inputOffset already recurses up to the original document, - // so that we don't have to call base.inputRegion on the produced region - return TextRegion.fromBothOffsets(inputOffset(outputRegion.getStartOffset(), true), - inputOffset(outputRegion.getEndOffset(), false)); - } - @Override public TextRegion createLineRange(int startLineInclusive, int endLineInclusive) { // see the doc, lines do not need to be translated @@ -61,15 +53,51 @@ abstract class BaseMappedDocument implements TextDocument { @Override public TextPos2d lineColumnAtOffset(int offset, boolean inclusive) { - return base.lineColumnAtOffset(localOffsetTransform(offset, inclusive)); + return base.lineColumnAtOffset(inputOffset(offset, inclusive)); } - @Override - public int inputOffset(int outOffset, boolean inclusive) { + /** + * Translate a region given in the coordinate system of this + * document, to the coordinate system of the base document. + * This works as if creating a new region with both start and end + * offsets translated through {@link #inputOffset(int, boolean)}. The + * returned region may have a different length. + * + * @param outputRegion Output region + * + * @return Input region + */ + protected @NonNull TextRegion inputRegion(TextRegion outputRegion) { + return TextRegion.fromBothOffsets(inputOffset(outputRegion.getStartOffset(), true), + inputOffset(outputRegion.getEndOffset(), false)); + } + + /** + * Returns the input offset for the given output offset. This maps + * back an offset in the coordinate system of this document, to the + * coordinate system of the base document. This includes the + * length of any unicode escapes. + * + *

    +     * input:      "a\u00a0b"   (original document)
    +     * translated: "a b"        (this document)
    +     *
    +     * translateOffset(0) = 0
    +     * translateOffset(1) = 1
    +     * translateOffset(2) = 7 // includes the length of the escape
    +     * 
    + * + * @param outOffset Output offset + * @param inclusive Whether the offset is to be interpreted as the index of a character (true), + * or the position after a character (false) + * + * @return Input offset + */ + protected final int inputOffset(int outOffset, boolean inclusive) { if (outOffset < 0 || outOffset > getLength()) { throw new IndexOutOfBoundsException(); } - return base.inputOffset(localOffsetTransform(outOffset, inclusive), inclusive); + return localOffsetTransform(outOffset, inclusive); } /** diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java index 32834826c2..74f42f29c5 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java @@ -588,6 +588,16 @@ public final class Chars implements CharSequence { return StreamSupport.stream(lines().spliterator(), false); } + /** + * Returns a new stringbuilder containing the whole contents of this + * char sequence. + */ + public StringBuilder toStringBuilder() { + StringBuilder sb = new StringBuilder(length()); + appendChars(sb); + return sb; + } + /** * Returns a new reader for the whole contents of this char sequence. diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/FragmentedTextDocument.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/FragmentedTextDocument.java index c3f372892a..009fbbd30b 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/FragmentedTextDocument.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/FragmentedTextDocument.java @@ -57,7 +57,7 @@ final class FragmentedTextDocument extends BaseMappedDocument implements TextDoc // Whether the fragment contains the offset we're looking for. // Will be true most of the time. boolean containsOffset = - f.outStart() >= outOffset && outOffset < f.outEnd(); + f.outStart() <= outOffset && outOffset < f.outEnd(); if (!containsOffset) { // Slow path, we must search for the fragment diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/RootTextDocument.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/RootTextDocument.java index 56ccfcd223..8dc79889ec 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/RootTextDocument.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/RootTextDocument.java @@ -119,16 +119,6 @@ final class RootTextDocument extends BaseCloseable implements TextDocument { return content.getCheckSum(); } - @Override - public int inputOffset(int outOffset, boolean inclusive) { - return outOffset; - } - - @Override - public TextRegion inputRegion(TextRegion outputRegion) { - return outputRegion; - } - @Override public Chars sliceOriginalText(TextRegion region) { return getText().subSequence(region.getStartOffset(), region.getEndOffset()); diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextDocument.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextDocument.java index 5003ed6a70..153f43e360 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextDocument.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextDocument.java @@ -144,43 +144,6 @@ public interface TextDocument extends Closeable { long getCheckSum(); - /** - * Returns the input offset for the given output offset. This maps - * back an offset in the coordinate system of this document, to the - * coordinate system of the original document. This includes the - * length of any unicode escapes. - * - *
    -     * input:      "a\u00a0b"   (original document)
    -     * translated: "a b"        (this document)
    -     *
    -     * translateOffset(0) = 0
    -     * translateOffset(1) = 1
    -     * translateOffset(2) = 7 // includes the length of the escape
    -     * 
    - * - * @param outOffset Output offset - * @param inclusive Whether the offset is to be interpreted as the index of a character (true), - * or the position after a character (false) - * - * @return Input offset - */ - int inputOffset(int outOffset, boolean inclusive); - - /** - * Translate a region given in the coordinate system of this - * document, to the coordinate system of the original document. - * This works as if creating a new region with both start and end - * offsets translated through {@link #inputOffset(int, boolean)}. The - * returned region may have a different length. - * - * @param outputRegion Output region - * - * @return Input region - */ - TextRegion inputRegion(TextRegion outputRegion); - - /** * Returns a reader over the text of this document. */ @@ -261,8 +224,6 @@ public interface TextDocument extends Closeable { * * @return A position, in the coordinate system of the root document * - * @return A position, in the coordinate system of this document - * * @throws IndexOutOfBoundsException if the offset is out of bounds */ TextPos2d lineColumnAtOffset(int offset, boolean inclusive); diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/CharsTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/CharsTest.java index 9fd02c3620..9365670f3d 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/CharsTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/CharsTest.java @@ -60,6 +60,14 @@ public class CharsTest { assertEquals("b", sb.toString()); } + @Test + public void toStringBuilder() { + Chars bc = Chars.wrap("abcd").slice(1, 2); + assertEquals("bc", bc.toString()); + + assertEquals("bc", bc.toStringBuilder().toString()); + } + @Test public void write() throws IOException { StringWriter writer = new StringWriter(); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStringLiteral.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStringLiteral.java index be73eccec1..6ea1ceb380 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStringLiteral.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStringLiteral.java @@ -9,7 +9,6 @@ import java.util.stream.Collectors; import org.apache.commons.lang3.StringEscapeUtils; import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; import net.sourceforge.pmd.lang.document.Chars; import net.sourceforge.pmd.util.CollectionUtil; @@ -31,6 +30,8 @@ public final class ASTStringLiteral extends AbstractLiteral implements ASTLitera } + // todo deprecate this + // it's ambiguous whether it returns getOriginalText or getTranslatedText @Override public String getImage() { return getText().toString(); @@ -72,12 +73,12 @@ public final class ASTStringLiteral extends AbstractLiteral implements ASTLitera } @Override - protected @Nullable Object buildConstValue() { + protected @NonNull Object buildConstValue() { if (isTextBlock()) { return determineTextBlockContent(getText()); } else { - CharSequence image = getText(); - CharSequence woDelims = image.subSequence(1, image.length() - 1); + Chars image = getText(); + Chars woDelims = image.subSequence(1, image.length() - 1); return StringEscapeUtils.UNESCAPE_JAVA.translate(woDelims); } } @@ -118,6 +119,7 @@ public final class ASTStringLiteral extends AbstractLiteral implements ASTLitera 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 + // todo octal escapes: https://docs.oracle.com/javase/specs/jls/se17/html/jls-3.html#jls-EscapeSequence for (int i = 0; i < sb.length(); i++) { char c = sb.charAt(i); if (c == '\\' && i < sb.length() - 1) { diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTLiteralTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTLiteralTest.kt index c2829ae510..7aec741c03 100644 --- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTLiteralTest.kt +++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTLiteralTest.kt @@ -4,6 +4,7 @@ package net.sourceforge.pmd.lang.java.ast +import io.kotest.matchers.shouldBe import net.sourceforge.pmd.lang.ast.test.NodeSpec import net.sourceforge.pmd.lang.ast.test.ValuedNodeSpec import net.sourceforge.pmd.lang.ast.test.shouldBe @@ -63,6 +64,7 @@ class ASTLiteralTest : ParserTestSpec({ } } } + suspend fun String.testTextBlock() { this.testTextBlock(EmptyAssertions) } @@ -166,7 +168,9 @@ $delim } "\"abc\\u1234abc\"" should parseAs { - stringLit("\"abc\\u1234abc\"") { + stringLit("\"abc\u1234abc\"") { + it.originalText.toString() shouldBe "\"abc\\u1234abc\"" + it.text.toString() shouldBe "\"abc\u1234abc\"" it::getConstValue shouldBe "abc\u1234abc" } } @@ -179,6 +183,19 @@ $delim } } + parserTest("String literal octal escapes") { + inContext(ExpressionParsingCtx) { + + "\"\\123\"" should parseAs { + stringLit("\"\\123\"") { + val char = "123".toInt(8).toChar() + it::getConstValue shouldBe char.toString() + } + } + + } + } + parserTest("Char literal") { From 76fe12d925f896d9b299ed1f386994b446016c9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sat, 30 Apr 2022 17:46:08 +0200 Subject: [PATCH 179/180] Recognize octal escapes in strings --- .../sourceforge/pmd/lang/document/Chars.java | 17 +- .../net/sourceforge/pmd/util/StringUtil.java | 15 ++ .../pmd/lang/java/ast/ASTStringLiteral.java | 192 +++++++++----- .../lang/java/ast/TextBlockEscapeTest.java | 249 ++++++++++++------ .../pmd/lang/java/ast/ASTLiteralTest.kt | 37 ++- .../pmd/lang/java/ast/TestExtensions.kt | 2 + 6 files changed, 356 insertions(+), 156 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java index 32834826c2..b929a9472c 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java @@ -121,26 +121,21 @@ public final class Chars implements CharSequence { } /** - * Appends the character range identified by offset and length into + * Appends the character range identified by start and end offset into * the string builder. This is much more efficient than calling * {@link StringBuilder#append(CharSequence)} with this as the * parameter, especially on Java 9+. * - *

    Be aware that {@link StringBuilder#append(CharSequence, int, int)} - * takes a start and end offset, whereas this method (like all - * the others in this class) take a start offset and a length. - * - * @param off Start (inclusive) - * @param len Number of characters + * @param start Start index (inclusive) + * @param end End index (exclusive) * * @throws IndexOutOfBoundsException See {@link StringBuilder#append(CharSequence, int, int)} */ - public void appendChars(StringBuilder sb, int off, int len) { - if (len == 0) { + public void appendChars(StringBuilder sb, int start, int end) { + if (end == 0) { return; } - int idx = idx(off); - sb.append(str, idx, idx + len); + sb.append(str, idx(start), idx(end)); } /** diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/StringUtil.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/StringUtil.java index 61e577c175..69215bb591 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/StringUtil.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/StringUtil.java @@ -148,6 +148,21 @@ public final class StringUtil { return col; } + /** + * Like {@link StringBuilder#append(CharSequence)}, but uses an optimized + * implementation if the charsequence happens to be a {@link Chars}. {@link StringBuilder} + * already optimises the cases where the charseq is a string, a StringBuilder, + * or a stringBuffer. This is especially useful in parsers. + */ + public static StringBuilder append(StringBuilder sb, CharSequence charSeq) { + if (charSeq instanceof Chars) { + ((Chars) charSeq).appendChars(sb); + return sb; + } else { + return sb.append(charSeq); + } + } + /** * Returns the substring following the last occurrence of the * given character. If the character doesn't occur, returns diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStringLiteral.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStringLiteral.java index be73eccec1..5b49e497d2 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStringLiteral.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStringLiteral.java @@ -7,12 +7,9 @@ package net.sourceforge.pmd.lang.java.ast; import java.util.List; import java.util.stream.Collectors; -import org.apache.commons.lang3.StringEscapeUtils; import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; import net.sourceforge.pmd.lang.document.Chars; -import net.sourceforge.pmd.util.CollectionUtil; import net.sourceforge.pmd.util.StringUtil; /** @@ -72,24 +69,35 @@ public final class ASTStringLiteral extends AbstractLiteral implements ASTLitera } @Override - protected @Nullable Object buildConstValue() { + protected @NonNull String buildConstValue() { if (isTextBlock()) { return determineTextBlockContent(getText()); } else { - CharSequence image = getText(); - CharSequence woDelims = image.subSequence(1, image.length() - 1); - return StringEscapeUtils.UNESCAPE_JAVA.translate(woDelims); + return determineStringContent(getText()); } } + static @NonNull String determineStringContent(Chars image) { + Chars woDelims = image.subSequence(1, image.length() - 1); + StringBuilder sb = new StringBuilder(woDelims.length()); + interpretEscapeSequences(woDelims, sb, false); + return sb.toString(); + } + static String determineTextBlockContent(Chars image) { List lines = getContentLines(image); // remove common prefix StringUtil.trimIndentInPlace(lines); - // join with normalized end of line - StringBuilder sb = CollectionUtil.joinCharsIntoStringBuilder(lines, "\n"); - // interpret escape sequences - interpretEscapeSequences(sb); + StringBuilder sb = new StringBuilder(image.length()); + for (int i = 0; i < lines.size(); i++) { + Chars line = lines.get(i); + boolean isLastLine = i == lines.size() - 1; + // this might return false if the line ends with a line continuation. + boolean appendNl = interpretEscapeSequences(line, sb, !isLastLine); + if (appendNl) { + sb.append('\n'); + } + } return sb.toString(); } @@ -115,57 +123,123 @@ public final class ASTStringLiteral extends AbstractLiteral implements ASTLitera return lines; } - private static void interpretEscapeSequences(StringBuilder sb) { - // interpret escape sequences "\" (line continuation), "n","t","b","r","f", "s", "\"", "\'", "\\" + /** + * Interpret escape sequences. This appends the interpreted contents + * of 'line' into the StringBuilder. The line does not contain any + * line terminators, instead, an implicit line terminator may be at + * the end (parameter {@code isEndANewLine}), to interpret line + * continuations. + * + * @param line Source line + * @param out Output + * @param isEndANewLine Whether the end of the line is a newline, + * as in text blocks + * + * @return Whether a newline should be appended at the end. Returns + * false if {@code isEndANewLine} and the line ends with a backslash, + * as this is a line continuation. + */ + // See https://docs.oracle.com/javase/specs/jls/se17/html/jls-3.html#jls-EscapeSequence + private static boolean interpretEscapeSequences(Chars line, StringBuilder out, boolean isEndANewLine) { // 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) { - 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 + int appended = 0; + int i = 0; + while (i < line.length()) { + char c = line.charAt(i); + if (c != '\\') { + i++; + continue; + } + if (i + 1 == line.length()) { + // the last character of the line is a backslash + if (isEndANewLine) { + // then this is a line continuation + line.appendChars(out, appended, i); + return false; // shouldn't append newline } + // otherwise we'll append the backslash when exiting the loop + break; + } + char cnext = line.charAt(i + 1); + switch (cnext) { + case '\\': + case 'n': + case 't': + case 'b': + case 'r': + case 'f': + case 's': + case '"': + case '\'': + // append up to and not including backslash + line.appendChars(out, appended, i); + // append the translation + out.append(translateBackslashEscape(cnext)); + // next time, start appending after the char + i += 2; + appended = i; + continue; + // octal digits + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + // append up to and not including backslash + line.appendChars(out, appended, i); + i = translateOctalEscape(line, i + 1, out); + appended = i; + continue; + default: + // unknown escape - do nothing - it stays + i++; + break; } } + + if (appended < line.length()) { + // append until the end + line.appendChars(out, appended, line.length()); + } + return isEndANewLine; + } + + private static char translateBackslashEscape(char c) { + switch (c) { + case '\\': return '\\'; + case 'n': return '\n'; + case 't': return '\t'; + case 'b': return '\b'; + case 'r': return '\r'; + case 'f': return '\f'; + case 's': return ' '; + case '"': return '"'; + case '\'': return '\''; + default: + throw new IllegalArgumentException("Not a valid escape \\" + c); + } + } + + private static int translateOctalEscape(Chars src, final int firstDigitIndex, StringBuilder sb) { + int i = firstDigitIndex; + int result = src.charAt(i) - '0'; + i++; + if (src.length() > i && isOctalDigit(src.charAt(i))) { + result = 8 * result + src.charAt(i) - '0'; + i++; + if (src.length() > i && isOctalDigit(src.charAt(i))) { + result = 8 * result + src.charAt(i) - '0'; + i++; + } + } + sb.append((char) result); + return i; + } + + private static boolean isOctalDigit(char c) { + return c >= '0' && c <= '7'; } } diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/TextBlockEscapeTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/TextBlockEscapeTest.java index 63f30f4510..1fb74b3099 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/TextBlockEscapeTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/TextBlockEscapeTest.java @@ -4,122 +4,209 @@ package net.sourceforge.pmd.lang.java.ast; +import static net.sourceforge.pmd.lang.java.ast.ASTStringLiteral.determineTextBlockContent; import static org.junit.Assert.assertEquals; +import org.checkerframework.checker.nullness.qual.NonNull; import org.junit.Test; +import net.sourceforge.pmd.lang.document.Chars; import net.sourceforge.pmd.lang.java.BaseParserTest; public class TextBlockEscapeTest extends BaseParserTest { + @Test + public void testStringEscapes() { + testStringEscape("abcd", "abcd"); + testStringEscape("abcd\\f", "abcd\f"); + testStringEscape("abcd\\n", "abcd\n"); + testStringEscape("abcd\\t", "abcd\t"); + testStringEscape("abcd\\bx", "abcd\bx"); + testStringEscape("abcd\\'x", "abcd\'x"); + // note that this one is actually invalid syntax + testStringEscape("abcd\\", "abcd\\"); + testStringEscape("abcd\\\\", "abcd\\"); + } + + @Test + public void testStringOctalEscapes() { + testStringEscape("\\0123", "\0123"); + testStringEscape("\\01ab", "\01ab"); + testStringEscape("\\0", "\0"); + } + + @Test + public void testStringUnknownEscape() { + testStringEscape("\\x", "\\x"); + } + + // note the argument order + private void testStringEscape(String actual, String expected) { + actual = inDoubleQuotes(actual); + assertEquals(expected, + ASTStringLiteral.determineStringContent(Chars.wrap(actual))); + } + + private static @NonNull String inDoubleQuotes(String expected) { + return "\"" + expected + "\""; + } + @Test public void testTextBlockContent() { - assertEquals("empty text block", "", - ASTStringLiteral.determineTextBlockContent("\"\"\"\n \"\"\"")); assertEquals("single line text block", "winter", - ASTStringLiteral.determineTextBlockContent("\"\"\"\n winter\"\"\"")); + determineTextBlockContent("\"\"\"\n winter\"\"\"")); assertEquals("single line text block with LF", "winter\n", - ASTStringLiteral.determineTextBlockContent("\"\"\"\n" - + " winter\n" - + " \"\"\"")); - assertEquals("basic text block example with html", - "\n" - + " \n" - + "

    Hello, world

    \n" - + " \n" - + "\n", - ASTStringLiteral.determineTextBlockContent("\"\"\"\n" - + " \n" - + " \n" - + "

    Hello, world

    \n" - + " \n" - + " \n" - + " \"\"\"")); + determineTextBlockContent("\"\"\"\n" + + " winter\n" + + " \"\"\"")); + assertEquals("single line text block with LF, some indent preserved", " winter\n", + determineTextBlockContent("\"\"\"\n" + + " winter\n" + + " \"\"\"")); + } + + @Test + public void emptyTextBlock() { + assertEquals("empty text block", "", + determineTextBlockContent("\"\"\"\n \"\"\"")); + } + + @Test + public void testEscapeBlockDelimiter() { + assertEquals("escaped text block in inside text block", + "String text = \"\"\"\n" + + " A text block inside a text block\n" + + "\"\"\";\n", + determineTextBlockContent("\"\"\"\n" + + " String text = \\\"\"\"\n" + + " A text block inside a text block\n" + + " \\\"\"\";\n" + + " \"\"\"")); + } + + @Test + public void testCrEscape() { assertEquals("text block with escapes", "\r\n" + " \r\n" + "

    Hello, world

    \r\n" + " \r\n" + "\r\n", - ASTStringLiteral.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", - ASTStringLiteral.determineTextBlockContent("\"\"\"\n" - + " String text = \\\"\"\"\n" - + " A text block inside a text block\n" - + " \\\"\"\";\n" - + " \"\"\"")); + determineTextBlockContent("\"\"\"\n" + + " \\r\n" + + " \\r\n" + + "

    Hello, world

    \\r\n" + + " \\r\n" + + " \\r\n" + + " \"\"\"")); + } + + @Test + public void testBasicHtmlBlock() { + assertEquals("basic text block example with html", + "\n" + + " \n" + + "

    Hello, world

    \n" + + " \n" + + "\n", + determineTextBlockContent("\"\"\"\n" + + " \n" + + " \n" + + "

    Hello, world

    \n" + + " \n" + + " \n" + + " \"\"\"")); + } + + @Test + public void testLineContinuation() { assertEquals("new escape: line continuation", "Lorem ipsum dolor sit amet, consectetur adipiscing " + "elit, sed do eiusmod tempor incididunt ut labore " + "et dolore magna aliqua.", - ASTStringLiteral.determineTextBlockContent("\"\"\"\n" - + " Lorem ipsum dolor sit amet, consectetur adipiscing \\\n" - + " elit, sed do eiusmod tempor incididunt ut labore \\\n" - + " et dolore magna aliqua.\\\n" - + " \"\"\"")); + determineTextBlockContent("\"\"\"\n" + + " Lorem ipsum dolor sit amet, consectetur adipiscing \\\n" + + " elit, sed do eiusmod tempor incididunt ut labore \\\n" + + " et dolore magna aliqua.\\\n" + + " \"\"\"")); + } + + @Test + public void testEscapeSpace() { + assertEquals("new escape: space escape", "red \n" + "green \n" + "blue \n", - ASTStringLiteral.determineTextBlockContent("\"\"\"\n" - + " red \\s\n" - + " green\\s\n" - + " blue \\s\n" - + " \"\"\"")); + determineTextBlockContent("\"\"\"\n" + + " red \\s\n" + + " green\\s\n" + + " blue \\s\n" + + " \"\"\"")); + + } + + @Test + public void testLineEndingNormalization() { assertEquals("with crlf line endings", "\n" + " \n" + "

    Hello, world

    \n" + " \n" - + "\n", ASTStringLiteral.determineTextBlockContent("\"\"\"\r\n" - + " \r\n" - + " \r\n" - + "

    Hello, world

    \r\n" - + " \r\n" - + " \r\n" - + " \"\"\"")); + + "\n", + 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", ASTStringLiteral.determineTextBlockContent("\"\"\"\r" - + " \r" - + " \r" - + "

    Hello, world

    \r" - + " \r" - + " \r" - + " \"\"\"")); - assertEquals("empty line directly after opening", - "\ntest\n", ASTStringLiteral.determineTextBlockContent("\"\"\"\n" - + " \n" - + " test\n" - + " \"\"\"")); - assertEquals("empty crlf line directly after opening", - "\ntest\n", ASTStringLiteral.determineTextBlockContent("\"\"\"\r\n" - + " \r\n" - + " test\r\n" - + " \"\"\"")); - assertEquals("empty line directly after opening without indentation", - "\ntest\n", ASTStringLiteral.determineTextBlockContent("\"\"\"\n" - + "\n" - + "test\n" - + "\"\"\"")); - assertEquals("empty crlf line directly after opening without indentation", - "\ntest\n", ASTStringLiteral.determineTextBlockContent("\"\"\"\r\n" - + "\r\n" - + "test\r\n" - + "\"\"\"")); - assertEquals("text block with backslash escape", "\\test\n", - ASTStringLiteral.determineTextBlockContent("\"\"\"\n \\\\test\n \"\"\"")); + + "\n", + determineTextBlockContent("\"\"\"\r" + + " \r" + + " \r" + + "

    Hello, world

    \r" + + " \r" + + " \r" + + " \"\"\"")); + } + + @Test + public void testEmptyLines() { + + assertEquals("empty line directly after opening", + "\ntest\n", determineTextBlockContent("\"\"\"\n" + + " \n" + + " test\n" + + " \"\"\"")); + assertEquals("empty crlf line directly after opening", + "\ntest\n", determineTextBlockContent("\"\"\"\r\n" + + " \r\n" + + " test\r\n" + + " \"\"\"")); + assertEquals("empty line directly after opening without indentation", + "\ntest\n", determineTextBlockContent("\"\"\"\n" + + "\n" + + "test\n" + + "\"\"\"")); + assertEquals("empty crlf line directly after opening without indentation", + "\ntest\n", determineTextBlockContent("\"\"\"\r\n" + + "\r\n" + + "test\r\n" + + "\"\"\"")); + + } + + @Test + public void testTextBlockWithBackslashEscape() { + assertEquals("text block with backslash escape", "\\test\n", + determineTextBlockContent("\"\"\"\n \\\\test\n \"\"\"")); + } + } diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTLiteralTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTLiteralTest.kt index c2829ae510..dfe6acc411 100644 --- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTLiteralTest.kt +++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTLiteralTest.kt @@ -63,6 +63,7 @@ class ASTLiteralTest : ParserTestSpec({ } } } + suspend fun String.testTextBlock() { this.testTextBlock(EmptyAssertions) } @@ -165,11 +166,12 @@ $delim } } - "\"abc\\u1234abc\"" should parseAs { - stringLit("\"abc\\u1234abc\"") { - it::getConstValue shouldBe "abc\u1234abc" - } - } + // todo fixed in followup branch + // "\"abc\\u1234abc\"" should parseAs { + // stringLit("\"abc\\u1234abc\"") { + // it::getConstValue shouldBe "abc\u1234abc" + // } + // } "\"abcüabc\"" should parseAs { stringLit("\"abcüabc\"") { @@ -179,6 +181,31 @@ $delim } } + parserTest("String literal octal escapes") { + inContext(ExpressionParsingCtx) { + // (kotlin doesn't have octal escapes) + val char = "123".toInt(radix = 8).toChar() + + "\"\\123\"" should parseAs { + stringLit("\"\\123\"") { + it::getConstValue shouldBe char.toString() + } + } + val delim = "\"\"\"" + + """ + $delim + \123 + $delim + """ should parseAs { + textBlock { + it::getConstValue shouldBe char.toString() + "\n" + } + } + + } + } + parserTest("Char literal") { diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/TestExtensions.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/TestExtensions.kt index 1a6cd74072..ae12f41d99 100644 --- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/TestExtensions.kt +++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/TestExtensions.kt @@ -437,6 +437,7 @@ fun TreeNodeWrapper.stringLit(image: String, contents: NodeSpec { it::getImage shouldBe image it::isTextBlock shouldBe false + it::isEmpty shouldBe it.constValue.isEmpty() contents() } @@ -468,6 +469,7 @@ fun TreeNodeWrapper.boolean(value: Boolean, contents: NodeSpec.textBlock(contents: NodeSpec = EmptyAssertions) = child { it::isTextBlock shouldBe true + it::isEmpty shouldBe it.constValue.isEmpty() contents() } From 87c224feaa504b75433a4a9ee5d704e755e30d02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sat, 30 Apr 2022 20:59:55 +0200 Subject: [PATCH 180/180] Fix AvoidDuplicateLiteral message needs escaping --- .../java/net/sourceforge/pmd/util/StringUtil.java | 4 ++++ .../pmd/lang/java/ast/ASTStringLiteral.java | 12 ++++++++++++ .../rule/errorprone/AvoidDuplicateLiteralsRule.java | 3 +-- .../pmd/lang/java/ast/TextBlockEscapeTest.java | 8 ++------ .../sourceforge/pmd/lang/java/ast/ASTLiteralTest.kt | 3 ++- 5 files changed, 21 insertions(+), 9 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/StringUtil.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/StringUtil.java index 69215bb591..5e50749cb0 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/StringUtil.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/StringUtil.java @@ -13,6 +13,7 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; +import org.checkerframework.checker.nullness.qual.NonNull; import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.internal.util.AssertionUtil; @@ -543,6 +544,9 @@ public final class StringUtil { return str.replaceAll("'", "''"); } + public static @NonNull String inDoubleQuotes(String expected) { + return "\"" + expected + "\""; + } public enum CaseConvention { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStringLiteral.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStringLiteral.java index dcec3d611a..651eefe415 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStringLiteral.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStringLiteral.java @@ -10,6 +10,7 @@ import java.util.stream.Collectors; import org.checkerframework.checker.nullness.qual.NonNull; import net.sourceforge.pmd.lang.document.Chars; +import net.sourceforge.pmd.lang.rule.xpath.NoAttribute; import net.sourceforge.pmd.util.StringUtil; /** @@ -58,6 +59,17 @@ public final class ASTStringLiteral extends AbstractLiteral implements ASTLitera return getConstValue().length(); } + /** + * Returns a string where non-printable characters have been escaped + * using Java-like escape codes (eg \n, \t, \u005cu00a0). + */ + // ^^^^^^ + // this is a backslash, it's printed as \u00a0 + @NoAttribute + public @NonNull String toPrintableString() { + return StringUtil.inDoubleQuotes(StringUtil.escapeJava(getConstValue())); + } + @Override protected R acceptVisitor(JavaVisitor visitor, P data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/AvoidDuplicateLiteralsRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/AvoidDuplicateLiteralsRule.java index b780b45a4c..3723278ed1 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/AvoidDuplicateLiteralsRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/AvoidDuplicateLiteralsRule.java @@ -88,8 +88,7 @@ public class AvoidDuplicateLiteralsRule extends AbstractJavaRulechainRule { SortedSet occurrences = entry.getValue(); if (occurrences.size() >= threshold) { ASTStringLiteral first = occurrences.first(); - String rawImage = first.getImage(); - Object[] args = {rawImage, occurrences.size(), first.getBeginLine(), }; + Object[] args = { first.toPrintableString(), occurrences.size(), first.getBeginLine(), }; addViolation(data, first, args); } } diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/TextBlockEscapeTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/TextBlockEscapeTest.java index 1fb74b3099..1a40b50605 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/TextBlockEscapeTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/TextBlockEscapeTest.java @@ -7,11 +7,11 @@ package net.sourceforge.pmd.lang.java.ast; import static net.sourceforge.pmd.lang.java.ast.ASTStringLiteral.determineTextBlockContent; import static org.junit.Assert.assertEquals; -import org.checkerframework.checker.nullness.qual.NonNull; import org.junit.Test; import net.sourceforge.pmd.lang.document.Chars; import net.sourceforge.pmd.lang.java.BaseParserTest; +import net.sourceforge.pmd.util.StringUtil; public class TextBlockEscapeTest extends BaseParserTest { @@ -42,15 +42,11 @@ public class TextBlockEscapeTest extends BaseParserTest { // note the argument order private void testStringEscape(String actual, String expected) { - actual = inDoubleQuotes(actual); + actual = StringUtil.inDoubleQuotes(actual); assertEquals(expected, ASTStringLiteral.determineStringContent(Chars.wrap(actual))); } - private static @NonNull String inDoubleQuotes(String expected) { - return "\"" + expected + "\""; - } - @Test public void testTextBlockContent() { assertEquals("single line text block", "winter", diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTLiteralTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTLiteralTest.kt index 909265b046..cdaae0c7d7 100644 --- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTLiteralTest.kt +++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTLiteralTest.kt @@ -168,8 +168,9 @@ $delim } "\"abc\\u1234abc\"" should parseAs { - stringLit("\"abc\\u1234abc\"") { + stringLit("\"abc\u1234abc\"") { it::getConstValue shouldBe "abc\u1234abc" + it.originalText.toString() shouldBe "\"abc\\u1234abc\"" } }

Note: the spec is described in + * String#stripIndent + * + * + * The minimum indentation (min) is determined as follows: + *