From 1b5f7e8baedb07e0ea2067adb384cddf3e100dea Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 13 May 2022 19:56:47 +0200 Subject: [PATCH] [core] Remember forced language per file Fixes #3970 --- docs/pages/release_notes.md | 2 ++ .../sourceforge/pmd/SourceCodeProcessor.java | 2 +- .../pmd/lang/LanguageVersionDiscoverer.java | 28 ++++++++++++--- .../pmd/lang/document/FileCollector.java | 4 ++- .../net/sourceforge/pmd/PmdAnalysisTest.java | 35 +++++++++++++++++++ .../pmd/lang/Dummy2LanguageModule.java | 4 +++ .../resources/sample-source/dummy/foo.txt | 1 + 7 files changed, 70 insertions(+), 6 deletions(-) create mode 100644 pmd-core/src/test/resources/sample-source/dummy/foo.txt diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index c31a705241..1770a48672 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -16,6 +16,8 @@ This is a {{ site.pmd.release_type }} release. ### Fixed Issues +* core + * [#3970](https://github.com/pmd/pmd/issues/3970): \[core] FileCollector.addFile ignores language parameter * javascript * [#3948](https://github.com/pmd/pmd/issues/3948): \[js] Invalid operator error for method property in object literal diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/SourceCodeProcessor.java b/pmd-core/src/main/java/net/sourceforge/pmd/SourceCodeProcessor.java index 7d1838c297..f52b0f2a2a 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/SourceCodeProcessor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/SourceCodeProcessor.java @@ -222,7 +222,7 @@ public class SourceCodeProcessor { ctx.setLanguageVersion(forceLanguage); } else { // otherwise determine by file extension - LanguageVersion languageVersion = configuration.getLanguageVersionOfFile(ctx.getSourceCodeFilename()); + LanguageVersion languageVersion = configuration.getLanguageVersionOfFile(ctx.getSourceCodeFile().toString()); ctx.setLanguageVersion(languageVersion); } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/LanguageVersionDiscoverer.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/LanguageVersionDiscoverer.java index 4e22b03a4f..27c72898e1 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/LanguageVersionDiscoverer.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/LanguageVersionDiscoverer.java @@ -5,6 +5,8 @@ package net.sourceforge.pmd.lang; import java.io.File; +import java.io.IOException; +import java.nio.file.Path; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -12,6 +14,7 @@ import java.util.Objects; import org.apache.commons.lang3.StringUtils; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.internal.util.AssertionUtil; /** @@ -24,6 +27,8 @@ public class LanguageVersionDiscoverer { private LanguageVersion forcedVersion; + private Map forcedVersionByFile = new HashMap<>(); + public LanguageVersionDiscoverer() { this(null); } @@ -97,10 +102,13 @@ public class LanguageVersionDiscoverer { * file. */ public LanguageVersion getDefaultLanguageVersionForFile(String fileName) { - List languages = getLanguagesForFile(fileName); - LanguageVersion languageVersion = null; - if (!languages.isEmpty()) { - languageVersion = getDefaultLanguageVersion(languages.get(0)); + LanguageVersion languageVersion = forcedVersionByFile.get(fileName); + + if (languageVersion == null) { + List languages = getLanguagesForFile(fileName); + if (!languages.isEmpty()) { + languageVersion = getDefaultLanguageVersion(languages.get(0)); + } } return languageVersion; } @@ -142,4 +150,16 @@ public class LanguageVersionDiscoverer { } + + @InternalApi + @Deprecated + public void recordLanguageVersionForFile(Path file, LanguageVersion languageVersion) { + String fileName; + try { + fileName = file.toRealPath().toString(); + } catch (IOException e) { + fileName = file.toAbsolutePath().toString(); + } + forcedVersionByFile.put(fileName, 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 8db97175c3..51d84106c4 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 @@ -155,8 +155,10 @@ public final class FileCollector implements AutoCloseable { reporter.error("Not a regular file {0}", file); return false; } - NioTextFile nioTextFile = new NioTextFile(file, charset, discoverer.getDefaultLanguageVersion(language), getDisplayName(file)); + LanguageVersion languageVersion = discoverer.getDefaultLanguageVersion(language); + NioTextFile nioTextFile = new NioTextFile(file, charset, languageVersion, getDisplayName(file)); addFileImpl(nioTextFile); + discoverer.recordLanguageVersionForFile(file, languageVersion); return true; } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/PmdAnalysisTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/PmdAnalysisTest.java index 4ec5555cf9..797f4e0569 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/PmdAnalysisTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/PmdAnalysisTest.java @@ -14,10 +14,17 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import java.io.IOException; +import java.nio.file.Paths; +import java.util.List; +import org.junit.Assert; import org.junit.Test; import org.mockito.ArgumentMatchers; +import net.sourceforge.pmd.lang.Dummy2LanguageModule; +import net.sourceforge.pmd.lang.Language; +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.rule.AbstractRule; import net.sourceforge.pmd.renderers.Renderer; /** @@ -72,4 +79,32 @@ public class PmdAnalysisTest { } } + @Test + public void testFileWithSpecificLanguage() { + final Language language = Dummy2LanguageModule.getInstance(); + PMDConfiguration config = new PMDConfiguration(); + config.setIgnoreIncrementalAnalysis(true); + RuleSet ruleset = RuleSet.forSingleRule(new TestRule()); + + try (PmdAnalysis pmd = PmdAnalysis.create(config)) { + pmd.addRuleSet(ruleset); + pmd.files().addFile(Paths.get("src", "test", "resources", "sample-source", "dummy", "foo.txt"), language); + Report report = pmd.performAnalysisAndCollectReport(); + Assert.assertEquals(0, report.getProcessingErrors().size()); + Assert.assertEquals(1, report.getViolations().size()); + } + } + + public static class TestRule extends AbstractRule { + public TestRule() { + setLanguage(Dummy2LanguageModule.getInstance()); + setMessage("dummy 2 test rule"); + } + + @Override + public void apply(List nodes, RuleContext ctx) { + ctx.addViolation(nodes.get(0)); + } + } + } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/Dummy2LanguageModule.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/Dummy2LanguageModule.java index e5a8de77cb..9d71d22010 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/Dummy2LanguageModule.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/Dummy2LanguageModule.java @@ -16,4 +16,8 @@ public class Dummy2LanguageModule extends BaseLanguageModule { super(NAME, null, TERSE_NAME, "dummy2"); addVersion("1.0", new DummyLanguageModule.Handler(), true); } + + public static Language getInstance() { + return LanguageRegistry.getLanguage(NAME); + } } diff --git a/pmd-core/src/test/resources/sample-source/dummy/foo.txt b/pmd-core/src/test/resources/sample-source/dummy/foo.txt new file mode 100644 index 0000000000..adaad87177 --- /dev/null +++ b/pmd-core/src/test/resources/sample-source/dummy/foo.txt @@ -0,0 +1 @@ +A dummy file with file extension txt.