diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexLanguageModule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexLanguageModule.java index 6a37f0e677..aa5882ba15 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexLanguageModule.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexLanguageModule.java @@ -8,6 +8,8 @@ import static net.sourceforge.pmd.util.CollectionUtil.listOf; import net.sourceforge.pmd.lang.BaseLanguageModule; import net.sourceforge.pmd.lang.Language; +import net.sourceforge.pmd.lang.LanguageProcessor; +import net.sourceforge.pmd.lang.LanguagePropertyBundle; import net.sourceforge.pmd.lang.LanguageRegistry; import apex.jorje.services.Version; @@ -19,7 +21,17 @@ public class ApexLanguageModule extends BaseLanguageModule { public ApexLanguageModule() { super(NAME, null, TERSE_NAME, listOf("cls", "trigger")); - addVersion(String.valueOf((int) Version.CURRENT.getExternal()), new ApexHandler(), true); + addVersion(String.valueOf((int) Version.CURRENT.getExternal()), new ApexLanguageProcessor(new ApexLanguageProperties()), true); + } + + @Override + public ApexLanguageProperties newPropertyBundle() { + return new ApexLanguageProperties(); + } + + @Override + public LanguageProcessor createProcessor(LanguagePropertyBundle bundle) { + return new ApexLanguageProcessor((ApexLanguageProperties) bundle); } public static Language getInstance() { diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexHandler.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexLanguageProcessor.java similarity index 79% rename from pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexHandler.java rename to pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexLanguageProcessor.java index ca41ee97c0..99f5f96ea8 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexHandler.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexLanguageProcessor.java @@ -9,7 +9,8 @@ import static net.sourceforge.pmd.util.CollectionUtil.setOf; import java.util.Set; import net.sourceforge.pmd.annotation.InternalApi; -import net.sourceforge.pmd.lang.AbstractPmdLanguageVersionHandler; +import net.sourceforge.pmd.lang.BatchLanguageProcessor; +import net.sourceforge.pmd.lang.LanguageVersionHandler; import net.sourceforge.pmd.lang.apex.ast.ApexParser; import net.sourceforge.pmd.lang.apex.internal.ApexDesignerBindings; import net.sourceforge.pmd.lang.apex.metrics.ApexMetrics; @@ -18,14 +19,18 @@ import net.sourceforge.pmd.lang.ast.Parser; import net.sourceforge.pmd.lang.metrics.LanguageMetricsProvider; import net.sourceforge.pmd.lang.metrics.Metric; import net.sourceforge.pmd.lang.rule.RuleViolationFactory; -import net.sourceforge.pmd.properties.PropertySource; import net.sourceforge.pmd.util.designerbindings.DesignerBindings; @InternalApi -public class ApexHandler extends AbstractPmdLanguageVersionHandler { +public class ApexLanguageProcessor + extends BatchLanguageProcessor + implements LanguageVersionHandler { private final ApexMetricsProvider myMetricsProvider = new ApexMetricsProvider(); + public ApexLanguageProcessor(ApexLanguageProperties bundle) { + super(ApexLanguageModule.getInstance(), bundle); + } @Override public RuleViolationFactory getRuleViolationFactory() { @@ -34,13 +39,7 @@ public class ApexHandler extends AbstractPmdLanguageVersionHandler { @Override public Parser getParser() { - return new ApexParser(); - } - - @Override - public void declareParserTaskProperties(PropertySource source) { - source.definePropertyDescriptor(ApexParser.MULTIFILE_DIRECTORY); - overridePropertiesFromEnv(ApexLanguageModule.TERSE_NAME, source); + return new ApexParser(getProperties()); } @Override diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexLanguageProperties.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexLanguageProperties.java new file mode 100644 index 0000000000..1b33565565 --- /dev/null +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexLanguageProperties.java @@ -0,0 +1,29 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex; + +import net.sourceforge.pmd.lang.LanguagePropertyBundle; +import net.sourceforge.pmd.properties.PropertyDescriptor; +import net.sourceforge.pmd.properties.PropertyFactory; + +/** + * @author Clément Fournier + */ +public class ApexLanguageProperties extends LanguagePropertyBundle { + + // todo change that to optional when properties are updated + public static final PropertyDescriptor MULTIFILE_DIRECTORY = + PropertyFactory.stringProperty("rootDirectory") + .desc("The root directory of the Salesforce metadata, where `sfdx-project.json` resides.") + .defaultValue("") // is this ok? + .build(); + + public ApexLanguageProperties() { + super(ApexLanguageModule.getInstance()); + definePropertyDescriptor(MULTIFILE_DIRECTORY); + } + + +} diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParser.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParser.java index ef356b4b19..25ae4b8155 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParser.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParser.java @@ -6,11 +6,10 @@ package net.sourceforge.pmd.lang.apex.ast; import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.apex.ApexJorjeLogging; +import net.sourceforge.pmd.lang.apex.ApexLanguageProperties; import net.sourceforge.pmd.lang.apex.multifile.ApexMultifileAnalysis; import net.sourceforge.pmd.lang.ast.ParseException; import net.sourceforge.pmd.lang.ast.Parser; -import net.sourceforge.pmd.properties.PropertyDescriptor; -import net.sourceforge.pmd.properties.PropertyFactory; import apex.jorje.data.Locations; import apex.jorje.semantic.ast.compilation.Compilation; @@ -18,15 +17,10 @@ import apex.jorje.semantic.ast.compilation.Compilation; @InternalApi public final class ApexParser implements Parser { - @InternalApi // todo change that to optional when properties are updated - public static final PropertyDescriptor MULTIFILE_DIRECTORY = - PropertyFactory.stringProperty("rootDirectory") - .desc("The root directory of the Salesforce metadata, where `sfdx-project.json` resides. " - + "Set environment variable PMD_APEX_ROOTDIRECTORY to use this.") - .defaultValue("") // is this ok? - .build(); + private final ApexLanguageProperties apexProperties; - public ApexParser() { + public ApexParser(ApexLanguageProperties apexProperties) { + this.apexProperties = apexProperties; ApexJorjeLogging.disableLogging(); Locations.useIndexFactory(); } @@ -41,11 +35,11 @@ public final class ApexParser implements Parser { throw new ParseException("Couldn't parse the source - there is not root node - Syntax Error??"); } - String property = task.getProperties().getProperty(MULTIFILE_DIRECTORY); + String property = apexProperties.getProperty(ApexLanguageProperties.MULTIFILE_DIRECTORY); ApexMultifileAnalysis analysisHandler = ApexMultifileAnalysis.getAnalysisInstance(property); - final ApexTreeBuilder treeBuilder = new ApexTreeBuilder(task); + final ApexTreeBuilder treeBuilder = new ApexTreeBuilder(task, apexProperties); return treeBuilder.buildTree(astRoot, analysisHandler); } catch (apex.jorje.services.exception.ParseException e) { throw new ParseException(e); 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 c6a4506dfb..7e6756fb5e 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 @@ -17,6 +17,7 @@ import java.util.function.Function; import java.util.regex.Matcher; import java.util.regex.Pattern; +import net.sourceforge.pmd.lang.apex.ApexLanguageProperties; import net.sourceforge.pmd.lang.apex.multifile.ApexMultifileAnalysis; import net.sourceforge.pmd.lang.ast.Parser.ParserTask; import net.sourceforge.pmd.lang.document.Chars; @@ -254,10 +255,10 @@ final class ApexTreeBuilder extends AstVisitor { private final ParserTask task; private final CommentInformation commentInfo; - ApexTreeBuilder(ParserTask task) { + ApexTreeBuilder(ParserTask task, ApexLanguageProperties apexProperties) { this.sourceCode = task.getTextDocument(); this.task = task; - commentInfo = extractInformationFromComments(sourceCode, task.getCommentMarker()); + commentInfo = extractInformationFromComments(sourceCode, apexProperties.getCommentMarker()); } static AbstractApexNode createNodeAdapter(T node) { diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/multifile/ApexMultifileAnalysis.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/multifile/ApexMultifileAnalysis.java index abee47ba64..2e27d28d3b 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/multifile/ApexMultifileAnalysis.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/multifile/ApexMultifileAnalysis.java @@ -16,7 +16,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.sourceforge.pmd.annotation.Experimental; -import net.sourceforge.pmd.lang.apex.ast.ApexParser; +import net.sourceforge.pmd.lang.apex.ApexLanguageProperties; import com.nawforce.common.api.FileIssueOptions; import com.nawforce.common.api.Org; @@ -101,7 +101,7 @@ public final class ApexMultifileAnalysis { * Returns the analysis instance. Returns a {@linkplain #isFailed() failed instance} * if this fails. * - * @param multiFileAnalysisDirectory Root directory of the configuration (see {@link ApexParser#MULTIFILE_DIRECTORY}). + * @param multiFileAnalysisDirectory Root directory of the configuration (see {@link ApexLanguageProperties#MULTIFILE_DIRECTORY}). */ public static @NonNull ApexMultifileAnalysis getAnalysisInstance(String multiFileAnalysisDirectory) { if (INSTANCE_MAP.isEmpty()) { 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 01ed36d138..5b005f20f5 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/PMDConfiguration.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/PMDConfiguration.java @@ -9,7 +9,9 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Properties; @@ -23,6 +25,8 @@ import net.sourceforge.pmd.cache.FileAnalysisCache; import net.sourceforge.pmd.cache.NoopAnalysisCache; import net.sourceforge.pmd.cli.PmdParametersParseResult; import net.sourceforge.pmd.internal.util.AssertionUtil; +import net.sourceforge.pmd.lang.Language; +import net.sourceforge.pmd.lang.LanguagePropertyBundle; import net.sourceforge.pmd.lang.LanguageRegistry; import net.sourceforge.pmd.lang.LanguageVersion; import net.sourceforge.pmd.lang.LanguageVersionDiscoverer; @@ -130,6 +134,7 @@ public class PMDConfiguration extends AbstractConfiguration { private boolean ignoreIncrementalAnalysis; private final LanguageRegistry langRegistry; private boolean progressBar = false; + private final Map langProperties = new HashMap<>(); public PMDConfiguration() { this(DEFAULT_REGISTRY); @@ -865,5 +870,16 @@ public class PMDConfiguration extends AbstractConfiguration { return progressBar; } - + /** + * Returns a mutable bundle of language properties that are associated + * to the given language (always the same for a given language). + * + * @param language A language, which must be registered + */ + public @NonNull LanguagePropertyBundle getLanguageProperties(Language language) { + if (!langRegistry.getLanguages().contains(language)) { + throw new IllegalArgumentException(language.getId()); + } + return langProperties.computeIfAbsent(language, Language::newPropertyBundle); + } } 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 e2e8601791..d3a787024f 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/PmdAnalysis.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/PmdAnalysis.java @@ -9,8 +9,10 @@ import static net.sourceforge.pmd.util.CollectionUtil.listOf; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; @@ -26,10 +28,12 @@ import net.sourceforge.pmd.cli.internal.CliMessages; 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.JvmLanguagePropertyBundle; import net.sourceforge.pmd.lang.Language; import net.sourceforge.pmd.lang.LanguageProcessor.AnalysisTask; import net.sourceforge.pmd.lang.LanguageProcessorRegistry; import net.sourceforge.pmd.lang.LanguageProcessorRegistry.LanguageTerminationException; +import net.sourceforge.pmd.lang.LanguagePropertyBundle; import net.sourceforge.pmd.lang.LanguageRegistry; import net.sourceforge.pmd.lang.LanguageVersion; import net.sourceforge.pmd.lang.LanguageVersionDiscoverer; @@ -85,6 +89,7 @@ public final class PmdAnalysis implements AutoCloseable { private final PMDConfiguration configuration; private final MessageReporter reporter; + private final Map langProperties = new HashMap<>(); private boolean closed; /** @@ -134,6 +139,19 @@ public final class PmdAnalysis implements AutoCloseable { final List ruleSets = ruleSetLoader.loadRuleSetsWithoutException(config.getRuleSetPaths()); pmd.addRuleSets(ruleSets); } + + for (Language language : config.languages()) { + LanguagePropertyBundle props = config.getLanguageProperties(language); + assert props.getLanguage().equals(language); + pmd.langProperties.put(language, props); + // TODO replace those with actual language properties when the + // CLI syntax is implemented. + props.setProperty(LanguagePropertyBundle.SUPPRESS_MARKER, config.getSuppressMarker()); + if (props instanceof JvmLanguagePropertyBundle) { + ((JvmLanguagePropertyBundle) props).setClassLoader(config.getClassLoader()); + } + } + return pmd; } @@ -241,6 +259,19 @@ public final class PmdAnalysis implements AutoCloseable { } + /** + * Returns a mutable bundle of language properties that are associated + * to the given language (always the same for a given language). + * + * @param language A language, which must be registered + */ + public LanguagePropertyBundle getLanguageProperties(Language language) { + if (!configuration.languages().getLanguages().contains(language)) { + throw new IllegalArgumentException(language.getId()); + } + return langProperties.computeIfAbsent(language, Language::newPropertyBundle); + } + /** * Run PMD with the current state of this instance. This will start * and finish the registered renderers, and close all @@ -309,8 +340,7 @@ public final class PmdAnalysis implements AutoCloseable { try (LanguageProcessorRegistry lpr = LanguageProcessorRegistry.create( // only start the applicable languages new LanguageRegistry(getApplicableLanguages()), - // todo - these come from the CLI (through the PMDConfiguration) - Collections.emptyMap(), + langProperties, reporter )) { AnalysisTask analysisTask = new AnalysisTask( diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/AbstractPmdLanguageVersionHandler.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/AbstractPmdLanguageVersionHandler.java index cf02bee9c2..8ba5ed5b30 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/AbstractPmdLanguageVersionHandler.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/AbstractPmdLanguageVersionHandler.java @@ -20,10 +20,20 @@ import net.sourceforge.pmd.properties.PropertySource; public abstract class AbstractPmdLanguageVersionHandler extends AbstractLanguageVersionHandler { + public static void readLanguagePropertiesFromEnv(LanguagePropertyBundle props) { + for (PropertyDescriptor propertyDescriptor : props.getPropertyDescriptors()) { + String propertyValue = getEnvValue(props.getLanguage().getTerseName(), propertyDescriptor); + + if (propertyValue != null) { + setPropertyCapture(props, propertyDescriptor, propertyValue); + } + } + } + /** * Returns the environment variable name that a user can set in order to override the default value. */ - String getEnvironmentVariableName(String langTerseName, PropertyDescriptor propertyDescriptor) { + static String getEnvironmentVariableName(String langTerseName, PropertyDescriptor propertyDescriptor) { if (langTerseName == null) { throw new IllegalStateException("Language is null"); } @@ -36,7 +46,7 @@ public abstract class AbstractPmdLanguageVersionHandler extends AbstractLanguage * variable has been set. */ - String getEnvValue(String langTerseName, PropertyDescriptor propertyDescriptor) { + static String getEnvValue(String langTerseName, PropertyDescriptor propertyDescriptor) { // note: since we use environent variables and not system properties, // tests override this method. return System.getenv(getEnvironmentVariableName(langTerseName, propertyDescriptor)); @@ -58,7 +68,7 @@ public abstract class AbstractPmdLanguageVersionHandler extends AbstractLanguage } @Deprecated - private void setPropertyCapture(PropertySource source, PropertyDescriptor propertyDescriptor, String propertyValue) { + private static void setPropertyCapture(PropertySource source, PropertyDescriptor propertyDescriptor, String propertyValue) { T value = propertyDescriptor.valueFrom(propertyValue); source.setProperty(propertyDescriptor, value); } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/BatchLanguageProcessor.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/BatchLanguageProcessor.java index fb7f7e7acb..948af22c43 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/BatchLanguageProcessor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/BatchLanguageProcessor.java @@ -9,23 +9,27 @@ import net.sourceforge.pmd.processor.AbstractPMDProcessor; /** * @author Clément Fournier */ -public class BatchLanguageProcessor implements LanguageProcessor { +public class BatchLanguageProcessor

implements LanguageProcessor { private final Language language; - private final LanguagePropertyBundle bundle; + private final P bundle; - public BatchLanguageProcessor(Language language, LanguagePropertyBundle bundle) { + public BatchLanguageProcessor(Language language, P bundle) { this.language = language; this.bundle = bundle; } + protected P getProperties() { + return bundle; + } + @Override public LanguageVersionHandler services() { return bundle.getLanguageVersion().getLanguageVersionHandler(); } @Override - public Language getLanguage() { + public final Language getLanguage() { return language; } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/JvmLanguagePropertyBundle.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/JvmLanguagePropertyBundle.java index 1d77cf74fe..64a58ccde1 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/JvmLanguagePropertyBundle.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/JvmLanguagePropertyBundle.java @@ -41,6 +41,10 @@ public class JvmLanguagePropertyBundle extends LanguagePropertyBundle { } } + public void setClassLoader(ClassLoader classLoader) { + this.classLoader = classLoader; + } + public @NonNull ClassLoader getAnalysisClassLoader() { if (classLoader == null) { classLoader = PMDConfiguration.class.getClassLoader(); diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/LanguageProcessorRegistry.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/LanguageProcessorRegistry.java index e8d606c720..afc90d9448 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/LanguageProcessorRegistry.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/LanguageProcessorRegistry.java @@ -50,13 +50,13 @@ public class LanguageProcessorRegistry implements Iterable, AutoClosea } public static LanguageProcessorRegistry create(LanguageRegistry registry, - Map languageProperties, + Map languageProperties, MessageReporter messageReporter) { Map processors = new HashMap<>(); for (Language language : registry) { - LanguagePropertyBundle properties = language.newPropertyBundle(); - setLanguageProperties(languageProperties, messageReporter, language, properties); + LanguagePropertyBundle properties = languageProperties.getOrDefault(language, language.newPropertyBundle()); try { + assert properties.getLanguage().equals(language): "Mismatched language"; LanguageProcessor processor = language.createProcessor(properties); processors.put(language, processor); } catch (IllegalArgumentException e) { @@ -67,6 +67,19 @@ public class LanguageProcessorRegistry implements Iterable, AutoClosea return new LanguageProcessorRegistry(processors); } + private static Map derivePropertiesFromStrings( + Map stringProperties, + MessageReporter reporter + ) { + Map typedProperties = new HashMap<>(); + stringProperties.forEach((l, props) -> { + LanguagePropertyBundle properties = l.newPropertyBundle(); + setLanguageProperties(stringProperties, reporter, l, properties); + }); + return typedProperties; + } + + private static void setLanguageProperties(Map languageProperties, MessageReporter messageReporter, Language language, LanguagePropertyBundle properties) { Properties props = languageProperties.get(language); if (props != null) { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/LanguagePropertyBundle.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/LanguagePropertyBundle.java index 7b08638257..813366f6e3 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/LanguagePropertyBundle.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/LanguagePropertyBundle.java @@ -57,7 +57,15 @@ public class LanguagePropertyBundle extends AbstractPropertySource { return language.getName(); } + public Language getLanguage() { + return language; + } + public LanguageVersion getLanguageVersion() { return getProperty(languageVersion); } + + public String getSuppressMarker() { + return getProperty(SUPPRESS_MARKER); + } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/Parser.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/Parser.java index ca252c0200..346c8d439c 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/Parser.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/Parser.java @@ -6,15 +6,8 @@ package net.sourceforge.pmd.lang.ast; import java.util.Objects; -import org.checkerframework.checker.nullness.qual.NonNull; - -import net.sourceforge.pmd.PMDConfiguration; import net.sourceforge.pmd.lang.LanguageVersion; import net.sourceforge.pmd.lang.document.TextDocument; -import net.sourceforge.pmd.properties.AbstractPropertySource; -import net.sourceforge.pmd.properties.PropertyDescriptor; -import net.sourceforge.pmd.properties.PropertyFactory; -import net.sourceforge.pmd.properties.PropertySource; /** * Produces an AST from a source file. Instances of this interface must @@ -44,38 +37,12 @@ public interface Parser { private final TextDocument textDoc; private final SemanticErrorReporter reporter; - private final ClassLoader auxclasspathClassLoader; - - private final PropertySource propertySource; - - public ParserTask(TextDocument textDoc, SemanticErrorReporter reporter, ClassLoader auxclasspathClassLoader) { - this.textDoc = Objects.requireNonNull(textDoc, "Text document was null"); - this.reporter = Objects.requireNonNull(reporter, "reporter was null"); - this.auxclasspathClassLoader = Objects.requireNonNull(auxclasspathClassLoader, "auxclasspathClassLoader was null"); - - this.propertySource = new ParserTaskProperties(); - propertySource.definePropertyDescriptor(COMMENT_MARKER); - } public ParserTask(TextDocument textDoc, SemanticErrorReporter reporter) { - this(textDoc, reporter, Parser.class.getClassLoader()); + this.textDoc = Objects.requireNonNull(textDoc, "Text document was null"); + this.reporter = Objects.requireNonNull(reporter, "reporter was null"); } - public static final PropertyDescriptor COMMENT_MARKER = - PropertyFactory.stringProperty("suppressionCommentMarker") - .desc("deprecated! NOPMD") - .defaultValue(PMDConfiguration.DEFAULT_SUPPRESS_MARKER) - .build(); - - @Deprecated // transitional until language properties are implemented - public PropertySource getProperties() { - return propertySource; - } - - @Deprecated // transitional until language properties are implemented - public ClassLoader getAuxclasspathClassLoader() { - return auxclasspathClassLoader; - } public LanguageVersion getLanguageVersion() { return textDoc.getLanguageVersion(); @@ -110,44 +77,7 @@ public interface Parser { return reporter; } - /** - * The suppression marker for comments. - */ - public @NonNull String getCommentMarker() { - return getProperties().getProperty(COMMENT_MARKER); - } - - private static final class ParserTaskProperties extends AbstractPropertySource { - - @Override - protected String getPropertySourceType() { - return "ParserOptions"; - } - - @Override - public String getName() { - return "n/a"; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (!(obj instanceof ParserTaskProperties)) { - return false; - } - final ParserTaskProperties that = (ParserTaskProperties) obj; - return Objects.equals(getPropertiesByPropertyDescriptor(), - that.getPropertiesByPropertyDescriptor()); - } - - @Override - public int hashCode() { - return getPropertiesByPropertyDescriptor().hashCode(); - } - } } 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 db36416f16..a4988b810f 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 @@ -21,7 +21,6 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import java.util.List; -import java.util.Properties; import java.util.function.BiConsumer; import org.junit.jupiter.api.BeforeEach; @@ -88,8 +87,8 @@ public class PmdRunnableTest { GlobalReportBuilderListener reportBuilder = new GlobalReportBuilderListener(); - Properties langProperties = new Properties(); - langProperties.setProperty(LanguagePropertyBundle.LANGUAGE_VERSION, lv.getVersion()); + LanguagePropertyBundle langProperties = lv.getLanguage().newPropertyBundle(); + langProperties.setLanguageVersion(lv.getVersion()); try (LanguageProcessorRegistry registry = LanguageProcessorRegistry.create(new LanguageRegistry(setOf(lv.getLanguage())), diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/JavaLanguageModule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/JavaLanguageModule.java index 25085f84b4..4e5e9bd95f 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/JavaLanguageModule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/JavaLanguageModule.java @@ -6,8 +6,12 @@ package net.sourceforge.pmd.lang.java; import net.sourceforge.pmd.lang.BaseLanguageModule; import net.sourceforge.pmd.lang.Language; +import net.sourceforge.pmd.lang.LanguageProcessor; +import net.sourceforge.pmd.lang.LanguagePropertyBundle; import net.sourceforge.pmd.lang.LanguageRegistry; import net.sourceforge.pmd.lang.java.internal.JavaLanguageHandler; +import net.sourceforge.pmd.lang.java.internal.JavaLanguageProcessor; +import net.sourceforge.pmd.lang.java.internal.JavaLanguageProperties; /** * Created by christoferdutz on 20.09.14. @@ -40,6 +44,17 @@ public class JavaLanguageModule extends BaseLanguageModule { addVersion("19-preview", new JavaLanguageHandler(19, true)); } + + @Override + public LanguagePropertyBundle newPropertyBundle() { + return new JavaLanguageProperties(); + } + + @Override + public LanguageProcessor createProcessor(LanguagePropertyBundle bundle) { + return new JavaLanguageProcessor((JavaLanguageProperties) bundle); + } + public static Language getInstance() { return LanguageRegistry.PMD.getLanguageByFullName(NAME); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParser.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParser.java index d8f8a5122a..2ff75dc9b8 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParser.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParser.java @@ -13,6 +13,7 @@ import net.sourceforge.pmd.lang.ast.impl.javacc.JjtreeParserAdapter; import net.sourceforge.pmd.lang.document.TextDocument; import net.sourceforge.pmd.lang.java.ast.internal.LanguageLevelChecker; import net.sourceforge.pmd.lang.java.internal.JavaAstProcessor; +import net.sourceforge.pmd.lang.java.internal.JavaLanguageProcessor; /** * Adapter for the JavaParser, using the specified grammar version. @@ -23,10 +24,17 @@ import net.sourceforge.pmd.lang.java.internal.JavaAstProcessor; public class JavaParser extends JjtreeParserAdapter { private final LanguageLevelChecker checker; + private final String suppressMarker; + private final JavaLanguageProcessor javaProcessor; private final boolean postProcess; - public JavaParser(LanguageLevelChecker checker, boolean postProcess) { + public JavaParser(LanguageLevelChecker checker, + String suppressMarker, + JavaLanguageProcessor javaProcessor, + boolean postProcess) { this.checker = checker; + this.suppressMarker = suppressMarker; + this.javaProcessor = javaProcessor; this.postProcess = postProcess; } @@ -44,7 +52,7 @@ public class JavaParser extends JjtreeParserAdapter { @Override protected ASTCompilationUnit parseImpl(CharStream cs, ParserTask task) throws ParseException { JavaParserImpl parser = new JavaParserImpl(cs); - parser.setSuppressMarker(task.getCommentMarker()); + parser.setSuppressMarker(suppressMarker); parser.setJdkVersion(checker.getJdkVersion()); parser.setPreview(checker.isPreviewEnabled()); @@ -53,9 +61,11 @@ public class JavaParser extends JjtreeParserAdapter { checker.check(root); if (postProcess) { - JavaAstProcessor processor = JavaAstProcessor.create(task.getAuxclasspathClassLoader(), - task.getLanguageVersion(), - task.getReporter()); + JavaAstProcessor processor = + javaProcessor != null ? JavaAstProcessor.create(javaProcessor, task.getReporter()) + : JavaAstProcessor.create(JavaParser.class.getClassLoader(), + task.getLanguageVersion(), + task.getReporter()); processor.process(root); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/internal/JavaAstProcessor.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/internal/JavaAstProcessor.java index 05c71238de..0b12c3b6ea 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/internal/JavaAstProcessor.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/internal/JavaAstProcessor.java @@ -222,6 +222,15 @@ public final class JavaAstProcessor { return create(classLoader, languageVersion, logger, defaultTypeInfLogger()); } + + public static JavaAstProcessor create(JavaLanguageProcessor globalProcessor, + SemanticErrorReporter semanticErrorReporter) { + return create(globalProcessor.getProperties().getAnalysisClassLoader(), + globalProcessor.getLanguageVersion(), + semanticErrorReporter, + defaultTypeInfLogger()); + } + public static JavaAstProcessor create(TypeSystem typeSystem, LanguageVersion languageVersion, SemanticErrorReporter semanticLogger, diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/internal/JavaLanguageHandler.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/internal/JavaLanguageHandler.java index 8052595681..7fd300a06b 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/internal/JavaLanguageHandler.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/internal/JavaLanguageHandler.java @@ -8,6 +8,7 @@ import static net.sourceforge.pmd.util.CollectionUtil.setOf; import java.util.Set; +import net.sourceforge.pmd.PMDConfiguration; import net.sourceforge.pmd.lang.AbstractPmdLanguageVersionHandler; import net.sourceforge.pmd.lang.ast.Parser; import net.sourceforge.pmd.lang.java.ast.JavaParser; @@ -59,11 +60,11 @@ public class JavaLanguageHandler extends AbstractPmdLanguageVersionHandler { @Override public Parser getParser() { - return new JavaParser(levelChecker, true); + return new JavaParser(levelChecker, PMDConfiguration.DEFAULT_SUPPRESS_MARKER, null, true); } public JavaParser getParserWithoutProcessing() { - return new JavaParser(levelChecker, false); + return new JavaParser(levelChecker, PMDConfiguration.DEFAULT_SUPPRESS_MARKER, null, false); } @Override diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/internal/JavaLanguageProcessor.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/internal/JavaLanguageProcessor.java new file mode 100644 index 0000000000..2f52880f14 --- /dev/null +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/internal/JavaLanguageProcessor.java @@ -0,0 +1,102 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.internal; + +import net.sourceforge.pmd.lang.BatchLanguageProcessor; +import net.sourceforge.pmd.lang.LanguageVersion; +import net.sourceforge.pmd.lang.LanguageVersionHandler; +import net.sourceforge.pmd.lang.ast.Parser; +import net.sourceforge.pmd.lang.java.JavaLanguageModule; +import net.sourceforge.pmd.lang.java.ast.JavaParser; +import net.sourceforge.pmd.lang.java.ast.internal.LanguageLevelChecker; +import net.sourceforge.pmd.lang.java.ast.internal.ReportingStrategy; +import net.sourceforge.pmd.lang.java.internal.JavaLanguageHandler.JavaMetricsProvider; +import net.sourceforge.pmd.lang.java.rule.internal.JavaRuleViolationFactory; +import net.sourceforge.pmd.lang.java.rule.xpath.internal.BaseContextNodeTestFun; +import net.sourceforge.pmd.lang.java.rule.xpath.internal.GetCommentOnFunction; +import net.sourceforge.pmd.lang.java.rule.xpath.internal.GetModifiersFun; +import net.sourceforge.pmd.lang.java.rule.xpath.internal.MatchesSignatureFunction; +import net.sourceforge.pmd.lang.java.rule.xpath.internal.MetricFunction; +import net.sourceforge.pmd.lang.java.rule.xpath.internal.NodeIsFunction; +import net.sourceforge.pmd.lang.metrics.LanguageMetricsProvider; +import net.sourceforge.pmd.lang.rule.RuleViolationFactory; +import net.sourceforge.pmd.lang.rule.xpath.impl.XPathHandler; +import net.sourceforge.pmd.util.designerbindings.DesignerBindings; + +/** + * @author Clément Fournier + */ +public class JavaLanguageProcessor extends BatchLanguageProcessor + implements LanguageVersionHandler { + + private final LanguageMetricsProvider myMetricsProvider = new JavaMetricsProvider(); + private final JavaParser parser; + + public JavaLanguageProcessor(JavaLanguageProperties properties) { + super(JavaLanguageModule.getInstance(), properties); + + LanguageLevelChecker levelChecker = + new LanguageLevelChecker<>(properties.getInternalJdkVersion(), + properties.isPreviewEnabled(), + // TODO change this strategy with a new lang property + ReportingStrategy.reporterThatThrows()); + + String suppressMarker = properties.getSuppressMarker(); + this.parser = new JavaParser(levelChecker, suppressMarker, this, true); + } + + @Override + public LanguageVersionHandler services() { + return this; + } + + @Override + public JavaLanguageProperties getProperties() { + return super.getProperties(); + } + + public LanguageVersion getLanguageVersion(){ + return getProperties().getLanguageVersion(); + } + + @Override + public Parser getParser() { + return parser; + } + + @Override + public DesignerBindings getDesignerBindings() { + return JavaDesignerBindings.INSTANCE; + } + + @Override + public XPathHandler getXPathHandler() { + return XPATH_HANDLER; + } + + @Override + public RuleViolationFactory getRuleViolationFactory() { + return JavaRuleViolationFactory.INSTANCE; + } + + + @Override + public LanguageMetricsProvider getLanguageMetricsProvider() { + return myMetricsProvider; + } + + private static final XPathHandler XPATH_HANDLER = + XPathHandler.getHandlerForFunctionDefs( + BaseContextNodeTestFun.TYPE_IS_EXACTLY, + BaseContextNodeTestFun.TYPE_IS, + BaseContextNodeTestFun.HAS_ANNOTATION, + MatchesSignatureFunction.INSTANCE, + NodeIsFunction.INSTANCE, + GetModifiersFun.GET_EFFECTIVE, + GetModifiersFun.GET_EXPLICIT, + MetricFunction.INSTANCE, + GetCommentOnFunction.INSTANCE + ); +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/internal/JavaLanguageProperties.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/internal/JavaLanguageProperties.java new file mode 100644 index 0000000000..b51cb642df --- /dev/null +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/internal/JavaLanguageProperties.java @@ -0,0 +1,37 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.internal; + +import net.sourceforge.pmd.lang.JvmLanguagePropertyBundle; +import net.sourceforge.pmd.lang.LanguageVersion; +import net.sourceforge.pmd.lang.java.JavaLanguageModule; + +/** + * @author Clément Fournier + */ +public class JavaLanguageProperties extends JvmLanguagePropertyBundle { + + public JavaLanguageProperties() { + super(JavaLanguageModule.getInstance()); + } + + boolean isPreviewEnabled() { + return getLanguageVersion().getVersion().endsWith("-preview"); + } + + int getInternalJdkVersion() { + // Todo that's ugly.. + LanguageVersion version = getLanguageVersion(); + String verString = version.getVersion(); + if (isPreviewEnabled()){ + verString = verString.substring(0, verString.length() - "-preview".length()); + } + if (verString.startsWith("1.")) + verString = verString.substring(2); + + return Integer.parseInt(verString); + } + +} diff --git a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/EcmascriptHandler.java b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/EcmascriptHandler.java deleted file mode 100644 index a5381e0de5..0000000000 --- a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/EcmascriptHandler.java +++ /dev/null @@ -1,24 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ecmascript; - -import net.sourceforge.pmd.lang.AbstractPmdLanguageVersionHandler; -import net.sourceforge.pmd.lang.ast.Parser; -import net.sourceforge.pmd.lang.ecmascript.ast.EcmascriptParser; - -class EcmascriptHandler extends AbstractPmdLanguageVersionHandler { - - private final int rhinoVersion; - - EcmascriptHandler(int rhinoVersion) { - this.rhinoVersion = rhinoVersion; - } - - @Override - public Parser getParser() { - return new EcmascriptParser(rhinoVersion); - } - -} diff --git a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/EcmascriptLanguageModule.java b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/EcmascriptLanguageModule.java index a7b7278b72..3a5a7423d7 100644 --- a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/EcmascriptLanguageModule.java +++ b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/EcmascriptLanguageModule.java @@ -4,9 +4,11 @@ package net.sourceforge.pmd.lang.ecmascript; -import org.mozilla.javascript.Context; - import net.sourceforge.pmd.lang.BaseLanguageModule; +import net.sourceforge.pmd.lang.Language; +import net.sourceforge.pmd.lang.LanguagePropertyBundle; +import net.sourceforge.pmd.lang.LanguageRegistry; +import net.sourceforge.pmd.lang.ecmascript.internal.EcmascriptProcessor; /** * Created by christoferdutz on 20.09.14. @@ -18,6 +20,10 @@ public class EcmascriptLanguageModule extends BaseLanguageModule { public EcmascriptLanguageModule() { super(NAME, null, TERSE_NAME, "js"); - addDefaultVersion("ES6", new EcmascriptHandler(Context.VERSION_ES6)); + addDefaultVersion("ES6", new EcmascriptProcessor(new LanguagePropertyBundle(this))); + } + + public static Language getInstance() { + return LanguageRegistry.PMD.getLanguageByFullName(NAME); } } diff --git a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/EcmascriptParser.java b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/EcmascriptParser.java index c71c6691a6..e06ae2344a 100644 --- a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/EcmascriptParser.java +++ b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/EcmascriptParser.java @@ -20,19 +20,20 @@ import net.sourceforge.pmd.lang.ast.AstInfo; import net.sourceforge.pmd.lang.ast.FileAnalysisException; import net.sourceforge.pmd.lang.ast.ParseException; import net.sourceforge.pmd.lang.ast.RootNode; +import net.sourceforge.pmd.lang.ecmascript.internal.EcmascriptProcessor; public final class EcmascriptParser implements net.sourceforge.pmd.lang.ast.Parser { - private final int esVersion; + private final EcmascriptProcessor processor; - public EcmascriptParser(int version) { - this.esVersion = version; + public EcmascriptParser(EcmascriptProcessor processor) { + this.processor = processor; } private AstRoot parseEcmascript(final String sourceCode, final List parseProblems) throws ParseException { final CompilerEnvirons compilerEnvirons = new CompilerEnvirons(); compilerEnvirons.setRecordingComments(true); compilerEnvirons.setRecordingLocalJsDocComments(true); - compilerEnvirons.setLanguageVersion(esVersion); + compilerEnvirons.setLanguageVersion(processor.getRhinoVersion()); // Scope's don't appear to get set right without this compilerEnvirons.setIdeMode(true); compilerEnvirons.setWarnTrailingComma(true); @@ -57,7 +58,7 @@ public final class EcmascriptParser implements net.sourceforge.pmd.lang.ast.Pars final EcmascriptTreeBuilder treeBuilder = new EcmascriptTreeBuilder(parseProblems); ASTAstRoot tree = (ASTAstRoot) treeBuilder.build(astRoot); - String suppressMarker = task.getCommentMarker(); + String suppressMarker = processor.getProperties().getSuppressMarker(); Map suppressMap = new HashMap<>(); if (astRoot.getComments() != null) { for (Comment comment : astRoot.getComments()) { diff --git a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/internal/EcmascriptProcessor.java b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/internal/EcmascriptProcessor.java new file mode 100644 index 0000000000..f29261e45e --- /dev/null +++ b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/internal/EcmascriptProcessor.java @@ -0,0 +1,37 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ecmascript.internal; + +import org.mozilla.javascript.Context; + +import net.sourceforge.pmd.lang.BatchLanguageProcessor; +import net.sourceforge.pmd.lang.LanguagePropertyBundle; +import net.sourceforge.pmd.lang.LanguageVersionHandler; +import net.sourceforge.pmd.lang.ast.Parser; +import net.sourceforge.pmd.lang.ecmascript.EcmascriptLanguageModule; +import net.sourceforge.pmd.lang.ecmascript.ast.EcmascriptParser; + +public class EcmascriptProcessor extends BatchLanguageProcessor + implements LanguageVersionHandler { + + public EcmascriptProcessor(LanguagePropertyBundle properties) { + super(EcmascriptLanguageModule.getInstance(), properties); + } + + public int getRhinoVersion() { + return Context.VERSION_ES6; + } + + @Override + public LanguagePropertyBundle getProperties() { + return super.getProperties(); + } + + @Override + public Parser getParser() { + return new EcmascriptParser(this); + } + +} diff --git a/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/BaseParsingHelper.kt b/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/BaseParsingHelper.kt index f3914a0e8b..82bea03f7e 100644 --- a/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/BaseParsingHelper.kt +++ b/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/BaseParsingHelper.kt @@ -133,13 +133,8 @@ abstract class BaseParsingHelper, T : RootNode fileName: String = TextFile.UNKNOWN_FILENAME ): T { val lversion = if (version == null) defaultVersion else getVersion(version) - val handler = lversion.languageVersionHandler val textDoc = TextDocument.readOnlyString(sourceCode, fileName, lversion) val task = Parser.ParserTask(textDoc, SemanticErrorReporter.noop()) - task.properties.also { - handler.declareParserTaskProperties(it) - it.setProperty(Parser.ParserTask.COMMENT_MARKER, params.suppressMarker) - } return doParse(params, task) } diff --git a/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/VfHandler.java b/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/VfHandler.java index 6a3858f6b6..0411a362e8 100644 --- a/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/VfHandler.java +++ b/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/VfHandler.java @@ -4,55 +4,20 @@ package net.sourceforge.pmd.lang.vf; -import java.io.File; -import java.util.Collections; -import java.util.List; - -import net.sourceforge.pmd.lang.AbstractPmdLanguageVersionHandler; +import net.sourceforge.pmd.lang.BatchLanguageProcessor; +import net.sourceforge.pmd.lang.LanguageVersionHandler; import net.sourceforge.pmd.lang.ast.Parser; import net.sourceforge.pmd.lang.vf.ast.VfParser; -import net.sourceforge.pmd.properties.PropertyDescriptor; -import net.sourceforge.pmd.properties.PropertyFactory; -import net.sourceforge.pmd.properties.PropertySource; -public class VfHandler extends AbstractPmdLanguageVersionHandler { +public class VfHandler extends BatchLanguageProcessor implements LanguageVersionHandler { - static final List DEFAULT_APEX_DIRECTORIES = Collections.singletonList(".." + File.separator + "classes"); - static final List DEFAULT_OBJECT_DIRECTORIES = Collections.singletonList(".." + File.separator + "objects"); - - /** - * Directory that contains Apex classes that may be referenced from a Visualforce page. - * - *

Env variable is {@code PMD_VF_APEXDIRECTORIES}. - */ - public static final PropertyDescriptor> APEX_DIRECTORIES_DESCRIPTOR = - PropertyFactory.stringListProperty("apexDirectories") - .desc("Location of Apex Class directories. Absolute or relative to the Visualforce directory.") - .defaultValue(DEFAULT_APEX_DIRECTORIES) - .delim(',') - .build(); - - /** - * Directory that contains Object definitions that may be referenced from a Visualforce page. - * - *

Env variable is {@code PMD_VF_OBJECTSDIRECTORIES}. - */ - public static final PropertyDescriptor> OBJECTS_DIRECTORIES_DESCRIPTOR = - PropertyFactory.stringListProperty("objectsDirectories") - .desc("Location of Custom Object directories. Absolute or relative to the Visualforce directory.") - .defaultValue(DEFAULT_OBJECT_DIRECTORIES) - .delim(',') - .build(); + public VfHandler(VfLanguageProperties bundle) { + super(VfLanguageModule.getInstance(), bundle); + } @Override public Parser getParser() { - return new VfParser(); + return new VfParser(getProperties()); } - @Override - public void declareParserTaskProperties(PropertySource source) { - source.definePropertyDescriptor(APEX_DIRECTORIES_DESCRIPTOR); - source.definePropertyDescriptor(OBJECTS_DIRECTORIES_DESCRIPTOR); - overridePropertiesFromEnv(VfLanguageModule.TERSE_NAME, source); - } } diff --git a/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/VfLanguageModule.java b/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/VfLanguageModule.java index 06e6403fa4..86b2c5fa3b 100644 --- a/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/VfLanguageModule.java +++ b/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/VfLanguageModule.java @@ -5,6 +5,8 @@ package net.sourceforge.pmd.lang.vf; import net.sourceforge.pmd.lang.BaseLanguageModule; +import net.sourceforge.pmd.lang.Language; +import net.sourceforge.pmd.lang.LanguageRegistry; /** @@ -18,6 +20,10 @@ public class VfLanguageModule extends BaseLanguageModule { public VfLanguageModule() { super(NAME, "VisualForce", TERSE_NAME, "page", "component"); - addVersion("", new VfHandler(), true); + addVersion("", new VfHandler(new VfLanguageProperties()), true); + } + + public static Language getInstance() { + return LanguageRegistry.PMD.getLanguageByFullName(NAME); } } diff --git a/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/VfLanguageProperties.java b/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/VfLanguageProperties.java new file mode 100644 index 0000000000..c14cab82d8 --- /dev/null +++ b/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/VfLanguageProperties.java @@ -0,0 +1,52 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.vf; + +import java.io.File; +import java.util.Collections; +import java.util.List; + +import net.sourceforge.pmd.lang.LanguagePropertyBundle; +import net.sourceforge.pmd.properties.PropertyDescriptor; +import net.sourceforge.pmd.properties.PropertyFactory; + +/** + * @author Clément Fournier + */ +public class VfLanguageProperties extends LanguagePropertyBundle { + + static final List DEFAULT_APEX_DIRECTORIES = Collections.singletonList(".." + File.separator + "classes"); + + /** + * Directory that contains Apex classes that may be referenced from a Visualforce page. + * + *

Env variable is {@code PMD_VF_APEXDIRECTORIES}. + */ + public static final PropertyDescriptor> APEX_DIRECTORIES_DESCRIPTOR = + PropertyFactory.stringListProperty("apexDirectories") + .desc("Location of Apex Class directories. Absolute or relative to the Visualforce directory.") + .defaultValue(DEFAULT_APEX_DIRECTORIES) + .delim(',') + .build(); + static final List DEFAULT_OBJECT_DIRECTORIES = Collections.singletonList(".." + File.separator + "objects"); + + /** + * Directory that contains Object definitions that may be referenced from a Visualforce page. + * + *

Env variable is {@code PMD_VF_OBJECTSDIRECTORIES}. + */ + public static final PropertyDescriptor> OBJECTS_DIRECTORIES_DESCRIPTOR = + PropertyFactory.stringListProperty("objectsDirectories") + .desc("Location of Custom Object directories. Absolute or relative to the Visualforce directory.") + .defaultValue(DEFAULT_OBJECT_DIRECTORIES) + .delim(',') + .build(); + + public VfLanguageProperties() { + super(VfLanguageModule.getInstance()); + definePropertyDescriptor(APEX_DIRECTORIES_DESCRIPTOR); + definePropertyDescriptor(OBJECTS_DIRECTORIES_DESCRIPTOR); + } +} diff --git a/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/ast/ApexClassPropertyTypes.java b/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/ast/ApexClassPropertyTypes.java index 60591c5ccc..eab303c55d 100644 --- a/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/ast/ApexClassPropertyTypes.java +++ b/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/ast/ApexClassPropertyTypes.java @@ -71,8 +71,7 @@ class ApexClassPropertyTypes extends SalesforceFieldTypes { TextDocument textDocument = TextDocument.create(file)) { Parser parser = languageVersion.getLanguageVersionHandler().getParser(); - ParserTask task = new ParserTask(textDocument, SemanticErrorReporter.noop(), ApexClassPropertyTypes.class.getClassLoader()); - languageVersion.getLanguageVersionHandler().declareParserTaskProperties(task.getProperties()); + ParserTask task = new ParserTask(textDocument, SemanticErrorReporter.noop()); return parser.parse(task); } catch (IOException e) { diff --git a/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/ast/VfExpressionTypeVisitor.java b/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/ast/VfExpressionTypeVisitor.java index e350e5e202..05ff049390 100644 --- a/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/ast/VfExpressionTypeVisitor.java +++ b/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/ast/VfExpressionTypeVisitor.java @@ -16,7 +16,7 @@ import org.slf4j.LoggerFactory; import net.sourceforge.pmd.lang.ast.Parser.ParserTask; import net.sourceforge.pmd.lang.vf.DataType; -import net.sourceforge.pmd.lang.vf.VfHandler; +import net.sourceforge.pmd.lang.vf.VfLanguageProperties; /** * Visits {@link ASTExpression} nodes and stores type information for @@ -45,10 +45,10 @@ class VfExpressionTypeVisitor extends VfParserVisitorAdapter { private final List apexDirectories; private final List objectsDirectories; - VfExpressionTypeVisitor(ParserTask task) { + VfExpressionTypeVisitor(ParserTask task, VfLanguageProperties vfProperties) { this.fileName = task.getFileDisplayName(); - this.apexDirectories = task.getProperties().getProperty(VfHandler.APEX_DIRECTORIES_DESCRIPTOR); - this.objectsDirectories = task.getProperties().getProperty(VfHandler.OBJECTS_DIRECTORIES_DESCRIPTOR); + this.apexDirectories = vfProperties.getProperty(VfLanguageProperties.APEX_DIRECTORIES_DESCRIPTOR); + this.objectsDirectories = vfProperties.getProperty(VfLanguageProperties.OBJECTS_DIRECTORIES_DESCRIPTOR); this.apexClassNames = new ArrayList<>(); this.apexClassPropertyTypes = new ApexClassPropertyTypes(); this.objectFieldTypes = new ObjectFieldTypes(); diff --git a/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/ast/VfParser.java b/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/ast/VfParser.java index 5ea1875558..0c828b38a1 100644 --- a/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/ast/VfParser.java +++ b/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/ast/VfParser.java @@ -11,12 +11,19 @@ import net.sourceforge.pmd.lang.ast.ParseException; import net.sourceforge.pmd.lang.ast.impl.javacc.JavaccTokenDocument; import net.sourceforge.pmd.lang.ast.impl.javacc.JjtreeParserAdapter; import net.sourceforge.pmd.lang.document.TextDocument; +import net.sourceforge.pmd.lang.vf.VfLanguageProperties; /** * Parser for the VisualForce language. */ public final class VfParser extends JjtreeParserAdapter { + private VfLanguageProperties vfProperties; + + public VfParser(VfLanguageProperties vfProperties) { + this.vfProperties = vfProperties; + } + @Override protected JavaccTokenDocument newDocumentImpl(TextDocument fullText) { return new JavaccTokenDocument(fullText) { @@ -32,7 +39,7 @@ public final class VfParser extends JjtreeParserAdapter { ASTCompilationUnit root = new VfParserImpl(cs).CompilationUnit().makeTaskInfo(task); // Add type information to the AST - VfExpressionTypeVisitor visitor = new VfExpressionTypeVisitor(task); + VfExpressionTypeVisitor visitor = new VfExpressionTypeVisitor(task, vfProperties); visitor.visit(root, null); return root; diff --git a/pmd-visualforce/src/test/java/net/sourceforge/pmd/lang/vf/ast/ApexClassPropertyTypesTest.java b/pmd-visualforce/src/test/java/net/sourceforge/pmd/lang/vf/ast/ApexClassPropertyTypesTest.java index ca0204d928..59582bbed4 100644 --- a/pmd-visualforce/src/test/java/net/sourceforge/pmd/lang/vf/ast/ApexClassPropertyTypesTest.java +++ b/pmd-visualforce/src/test/java/net/sourceforge/pmd/lang/vf/ast/ApexClassPropertyTypesTest.java @@ -17,7 +17,7 @@ import org.junit.Test; import net.sourceforge.pmd.lang.vf.DataType; import net.sourceforge.pmd.lang.vf.VFTestUtils; -import net.sourceforge.pmd.lang.vf.VfHandler; +import net.sourceforge.pmd.lang.vf.VfLanguageProperties; public class ApexClassPropertyTypesTest { private static final Map EXPECTED_DATA_TYPES; @@ -58,7 +58,7 @@ public class ApexClassPropertyTypesTest { ApexClassPropertyTypes apexClassPropertyTypes = new ApexClassPropertyTypes(); ObjectFieldTypesTest.validateDataTypes(EXPECTED_DATA_TYPES, apexClassPropertyTypes, vfPagePath, - VfHandler.APEX_DIRECTORIES_DESCRIPTOR.defaultValue()); + VfLanguageProperties.APEX_DIRECTORIES_DESCRIPTOR.defaultValue()); } @Test diff --git a/pmd-visualforce/src/test/java/net/sourceforge/pmd/lang/vf/ast/ObjectFieldTypesTest.java b/pmd-visualforce/src/test/java/net/sourceforge/pmd/lang/vf/ast/ObjectFieldTypesTest.java index 26de0aac96..d520f8358f 100644 --- a/pmd-visualforce/src/test/java/net/sourceforge/pmd/lang/vf/ast/ObjectFieldTypesTest.java +++ b/pmd-visualforce/src/test/java/net/sourceforge/pmd/lang/vf/ast/ObjectFieldTypesTest.java @@ -19,7 +19,7 @@ import org.junit.Test; import net.sourceforge.pmd.lang.vf.DataType; import net.sourceforge.pmd.lang.vf.VFTestUtils; -import net.sourceforge.pmd.lang.vf.VfHandler; +import net.sourceforge.pmd.lang.vf.VfLanguageProperties; public class ObjectFieldTypesTest { private static final Map EXPECTED_SFDX_DATA_TYPES; @@ -57,7 +57,7 @@ public class ObjectFieldTypesTest { Path vfPagePath = VFTestUtils.getMetadataPath(this, VFTestUtils.MetadataFormat.SFDX, VFTestUtils.MetadataType.Vf).resolve("SomePage.page"); ObjectFieldTypes objectFieldTypes = new ObjectFieldTypes(); - validateSfdxAccount(objectFieldTypes, vfPagePath, VfHandler.OBJECTS_DIRECTORIES_DESCRIPTOR.defaultValue()); + validateSfdxAccount(objectFieldTypes, vfPagePath, VfLanguageProperties.OBJECTS_DIRECTORIES_DESCRIPTOR.defaultValue()); } /** @@ -68,7 +68,7 @@ public class ObjectFieldTypesTest { Path vfPagePath = VFTestUtils.getMetadataPath(this, VFTestUtils.MetadataFormat.MDAPI, VFTestUtils.MetadataType.Vf).resolve("SomePage.page"); ObjectFieldTypes objectFieldTypes = new ObjectFieldTypes(); - validateMDAPIAccount(objectFieldTypes, vfPagePath, VfHandler.OBJECTS_DIRECTORIES_DESCRIPTOR.defaultValue()); + validateMDAPIAccount(objectFieldTypes, vfPagePath, VfLanguageProperties.OBJECTS_DIRECTORIES_DESCRIPTOR.defaultValue()); } /** @@ -80,8 +80,8 @@ public class ObjectFieldTypesTest { Path vfPagePath = VFTestUtils.getMetadataPath(this, VFTestUtils.MetadataFormat.SFDX, VFTestUtils.MetadataType.Vf) .resolve("SomePage.page"); - List paths = Arrays.asList(VfHandler.OBJECTS_DIRECTORIES_DESCRIPTOR.defaultValue().get(0), - VFTestUtils.getMetadataPath(this, VFTestUtils.MetadataFormat.MDAPI, VFTestUtils.MetadataType.Objects).toString()); + List paths = Arrays.asList(VfLanguageProperties.OBJECTS_DIRECTORIES_DESCRIPTOR.defaultValue().get(0), + VFTestUtils.getMetadataPath(this, VFTestUtils.MetadataFormat.MDAPI, VFTestUtils.MetadataType.Objects).toString()); objectFieldTypes = new ObjectFieldTypes(); validateSfdxAccount(objectFieldTypes, vfPagePath, paths); validateMDAPIAccount(objectFieldTypes, vfPagePath, paths);