diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexHandler.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexHandler.java index b2d57eb9c9..9fda894220 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexHandler.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexHandler.java @@ -39,7 +39,7 @@ public class ApexHandler extends AbstractPmdLanguageVersionHandler { @Override public Parser getParser(ParserOptions parserOptions) { - return new ApexParser(parserOptions); + return new ApexParser(); } 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 2ab9bd8497..66fd4756a1 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 @@ -4,14 +4,8 @@ package net.sourceforge.pmd.lang.apex.ast; -import java.io.IOException; -import java.io.Reader; - -import org.apache.commons.io.IOUtils; - import net.sourceforge.pmd.annotation.InternalApi; -import net.sourceforge.pmd.lang.AbstractParser; -import net.sourceforge.pmd.lang.ParserOptions; +import net.sourceforge.pmd.lang.Parser; import net.sourceforge.pmd.lang.apex.ApexJorjeLogging; import net.sourceforge.pmd.lang.ast.ParseException; import net.sourceforge.pmd.lang.ast.RootNode; @@ -21,31 +15,30 @@ import apex.jorje.data.Locations; import apex.jorje.semantic.ast.compilation.Compilation; @InternalApi -public final class ApexParser extends AbstractParser { +public final class ApexParser implements Parser { - public ApexParser(ParserOptions parserOptions) { - super(parserOptions); + public ApexParser() { ApexJorjeLogging.disableLogging(); Locations.useIndexFactory(); } @Override - public RootNode parse(final String filename, final Reader reader) { + public RootNode parse(final ParserTask task) { try { - final String sourceCode = IOUtils.toString(reader); - final Compilation astRoot = CompilerService.INSTANCE.parseApex(filename, sourceCode); + String sourceCode = task.getSourceText(); + final Compilation astRoot = CompilerService.INSTANCE.parseApex(task.getFileDisplayName(), sourceCode); if (astRoot == null) { throw new ParseException("Couldn't parse the source - there is not root node - Syntax Error??"); } SourceCodePositioner positioner = new SourceCodePositioner(sourceCode); - final ApexTreeBuilder treeBuilder = new ApexTreeBuilder(sourceCode, getParserOptions(), positioner); + final ApexTreeBuilder treeBuilder = new ApexTreeBuilder(sourceCode, task.getCommentMarker(), positioner); AbstractApexNode treeRoot = treeBuilder.build(astRoot); ASTApexFile fileNode = new ASTApexFile(positioner, treeRoot); fileNode.setNoPmdComments(treeBuilder.getSuppressMap()); return fileNode; - } catch (IOException | apex.jorje.services.exception.ParseException e) { + } 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 dc839dafe5..773d6d8d33 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 @@ -15,7 +15,6 @@ import java.util.Stack; import org.antlr.runtime.ANTLRStringStream; import org.antlr.runtime.Token; -import net.sourceforge.pmd.lang.ParserOptions; import net.sourceforge.pmd.lang.ast.SourceCodePositioner; import apex.jorje.data.Location; @@ -245,11 +244,11 @@ final class ApexTreeBuilder extends AstVisitor { private final List apexDocTokenLocations; private final Map suppressMap; - ApexTreeBuilder(String sourceCode, ParserOptions parserOptions, SourceCodePositioner positioner) { + ApexTreeBuilder(String sourceCode, String suppressMarker, SourceCodePositioner positioner) { this.sourceCode = sourceCode; sourceCodePositioner = positioner; - CommentInformation commentInformation = extractInformationFromComments(sourceCode, parserOptions.getSuppressMarker()); + CommentInformation commentInformation = extractInformationFromComments(sourceCode, suppressMarker); apexDocTokenLocations = commentInformation.docTokenLocations; suppressMap = commentInformation.suppressMap; } 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 32644b1bec..dc0a292cce 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/PMD.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/PMD.java @@ -34,12 +34,7 @@ import net.sourceforge.pmd.lang.Language; import net.sourceforge.pmd.lang.LanguageFilenameFilter; import net.sourceforge.pmd.lang.LanguageVersion; import net.sourceforge.pmd.lang.LanguageVersionDiscoverer; -import net.sourceforge.pmd.lang.LanguageVersionHandler; -import net.sourceforge.pmd.lang.Parser; -import net.sourceforge.pmd.lang.ParserOptions; import net.sourceforge.pmd.processor.AbstractPMDProcessor; -import net.sourceforge.pmd.processor.MonoThreadProcessor; -import net.sourceforge.pmd.processor.MultiThreadProcessor; import net.sourceforge.pmd.renderers.Renderer; import net.sourceforge.pmd.util.ClasspathClassLoader; import net.sourceforge.pmd.util.FileUtil; @@ -76,8 +71,6 @@ public class PMD { */ protected final PMDConfiguration configuration; - private final SourceCodeProcessor rulesetsFileProcessor; - /** * Constant that contains always the current version of PMD. * @deprecated Use {@link PMDVersion#VERSION} instead. @@ -101,7 +94,6 @@ public class PMD { */ public PMD(PMDConfiguration configuration) { this.configuration = configuration; - this.rulesetsFileProcessor = new SourceCodeProcessor(configuration); } /** @@ -151,27 +143,6 @@ public class PMD { return dataSources; } - /** - * Helper method to get a configured parser for the requested language. The - * parser is configured based on the given {@link PMDConfiguration}. - * - * @param languageVersion - * the requested language - * @param configuration - * the given configuration - * @return the pre-configured parser - */ - public static Parser parserFor(LanguageVersion languageVersion, PMDConfiguration configuration) { - - // TODO Handle Rules having different parser options. - LanguageVersionHandler languageVersionHandler = languageVersion.getLanguageVersionHandler(); - ParserOptions options = languageVersionHandler.getDefaultParserOptions(); - if (configuration != null) { - options.setSuppressMarker(configuration.getSuppressMarker()); - } - return languageVersionHandler.getParser(options); - } - /** * Get the runtime configuration. The configuration can be modified to * affect how PMD behaves. @@ -183,15 +154,6 @@ public class PMD { return configuration; } - /** - * Gets the source code processor. - * - * @return SourceCodeProcessor - */ - public SourceCodeProcessor getSourceCodeProcessor() { - return rulesetsFileProcessor; - } - /** * This method is the main entry point for command line usage. * @@ -233,6 +195,7 @@ public class PMD { }); try (TimedOperation to = TimeTracker.startOperation(TimedOperationCategory.FILE_PROCESSING)) { + encourageToUseIncrementalAnalysis(configuration); processFiles(configuration, ruleSetFactory, files, ctx, renderers); } @@ -295,18 +258,56 @@ public class PMD { * @param renderers * List of {@link Renderer}s */ - public static void processFiles(final PMDConfiguration configuration, final RuleSetFactory ruleSetFactory, - final List files, final RuleContext ctx, final List renderers) { + public static void processFiles(final PMDConfiguration configuration, + final RuleSetFactory ruleSetFactory, + final List files, + final RuleContext ctx, + final List renderers) { + + final RuleSetFactory silentFactory = new RuleSetFactory(ruleSetFactory, false); + + final RuleSets rs = RulesetsFactoryUtils.getRuleSets(configuration.getRuleSets(), silentFactory); + + final Set brokenRules = removeBrokenRules(rs); + for (final Rule rule : brokenRules) { + ctx.getReport().addConfigError(new Report.ConfigurationError(rule, rule.dysfunctionReason())); + } + encourageToUseIncrementalAnalysis(configuration); sortFiles(configuration, files); // Make sure the cache is listening for analysis results ctx.getReport().addListener(configuration.getAnalysisCache()); - final RuleSetFactory silentFactory = new RuleSetFactory(ruleSetFactory, false); - newFileProcessor(configuration).processFiles(silentFactory, files, ctx, renderers); + configuration.getAnalysisCache().checkValidity(rs, configuration.getClassLoader()); + + AbstractPMDProcessor.newFileProcessor(configuration).processFiles(rs, files, ctx, renderers); configuration.getAnalysisCache().persist(); } + + /** + * Remove and return the misconfigured rules from the rulesets and log them + * for good measure. + * + * @param ruleSets RuleSets to prune of broken rules. + * + * @return Set + */ + private static Set removeBrokenRules(final RuleSets ruleSets) { + final Set brokenRules = new HashSet<>(); + ruleSets.removeDysfunctionalRules(brokenRules); + + for (final Rule rule : brokenRules) { + if (LOG.isLoggable(Level.WARNING)) { + LOG.log(Level.WARNING, + "Removed misconfigured rule: " + rule.getName() + " cause: " + rule.dysfunctionReason()); + } + } + + return brokenRules; + } + + private static void sortFiles(final PMDConfiguration configuration, final List files) { if (configuration.isStressTest()) { // randomize processing order @@ -336,15 +337,6 @@ public class PMD { } } - /* - * Check if multithreaded support is available. ExecutorService can also - * be disabled if threadCount is not positive, e.g. using the - * "-threads 0" command line option. - */ - private static AbstractPMDProcessor newFileProcessor(final PMDConfiguration configuration) { - return configuration.getThreads() > 0 ? new MultiThreadProcessor(configuration) : new MonoThreadProcessor(configuration); - } - /** * Determines all the files, that should be analyzed by PMD. * 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 5690591011..de7bfd2001 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/RuleContext.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/RuleContext.java @@ -50,6 +50,7 @@ public class RuleContext { */ public RuleContext(RuleContext ruleContext) { this.report.addListeners(ruleContext.getReport().getListeners()); + this.setIgnoreExceptions(ruleContext.ignoreExceptions); } /** @@ -97,7 +98,11 @@ public class RuleContext { * If there is no source file, then an empty string is returned. * * @return The file name. + * + * @deprecated Will be replaced by the document API. Nodes will + * have access to their document. */ + @Deprecated public String getSourceCodeFilename() { if (sourceCodeFile != null) { return sourceCodeFile.getName(); @@ -125,7 +130,11 @@ public class RuleContext { * Get the LanguageVersion associated with the current source file. * * @return The LanguageVersion, null if unknown. + * + * @deprecated Will be replaced by a method on Node (nodes will + * know their language version). */ + @Deprecated public LanguageVersion getLanguageVersion() { return this.languageVersion; } @@ -138,6 +147,7 @@ public class RuleContext { * @param languageVersion * The LanguageVersion. */ + @Deprecated public void setLanguageVersion(LanguageVersion languageVersion) { this.languageVersion = languageVersion; } @@ -169,4 +179,10 @@ public class RuleContext { public boolean isIgnoreExceptions() { return ignoreExceptions; } + + public static RuleContext throwingExceptions() { + RuleContext ctx = new RuleContext(); + ctx.setIgnoreExceptions(false); + return ctx; + } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/SourceCodeProcessor.java b/pmd-core/src/main/java/net/sourceforge/pmd/SourceCodeProcessor.java deleted file mode 100644 index b0127e5ba4..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/SourceCodeProcessor.java +++ /dev/null @@ -1,175 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd; - -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.util.Collections; - -import net.sourceforge.pmd.benchmark.TimeTracker; -import net.sourceforge.pmd.benchmark.TimedOperation; -import net.sourceforge.pmd.benchmark.TimedOperationCategory; -import net.sourceforge.pmd.internal.RulesetStageDependencyHelper; -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.ParseException; -import net.sourceforge.pmd.lang.ast.RootNode; - -public class SourceCodeProcessor { - - private final PMDConfiguration configuration; - private final RulesetStageDependencyHelper dependencyHelper; - - - public SourceCodeProcessor(PMDConfiguration configuration) { - this.configuration = configuration; - dependencyHelper = new RulesetStageDependencyHelper(configuration); - } - - /** - * Processes the input stream against a rule set using the given input - * encoding. - * - * @param sourceCode - * The InputStream to analyze. - * @param ruleSets - * The collection of rules to process against the file. - * @param ctx - * The context in which PMD is operating. - * @throws PMDException - * if the input encoding is unsupported, the input stream could - * not be parsed, or other error is encountered. - * @see #processSourceCode(Reader, RuleSets, RuleContext) - */ - public void processSourceCode(InputStream sourceCode, RuleSets ruleSets, RuleContext ctx) throws PMDException { - try (Reader streamReader = new InputStreamReader(sourceCode, configuration.getSourceEncoding())) { - processSourceCode(streamReader, ruleSets, ctx); - } catch (IOException e) { - throw new PMDException("IO exception: " + e.getMessage(), e); - } - } - - /** - * Processes the input stream against a rule set using the given input - * encoding. If the LanguageVersion is null on the RuleContext, - * it will be automatically determined. Any code which wishes to process - * files for different Languages, will need to be sure to either properly - * set the Language on the RuleContext, or set it to null - * first. - * - * @see RuleContext#setLanguageVersion(net.sourceforge.pmd.lang.LanguageVersion) - * @see PMDConfiguration#getLanguageVersionOfFile(String) - * - * @param sourceCode - * The Reader to analyze. - * @param ruleSets - * The collection of rules to process against the file. - * @param ctx - * The context in which PMD is operating. - * @throws PMDException - * if the input encoding is unsupported, the input stream could - * not be parsed, or other error is encountered. - */ - public void processSourceCode(Reader sourceCode, RuleSets ruleSets, RuleContext ctx) throws PMDException { - determineLanguage(ctx); - - // Coarse check to see if any RuleSet applies to file, will need to do a finer RuleSet specific check later - if (ruleSets.applies(ctx.getSourceCodeFile())) { - if (isCacheUpToDate(ctx)) { - reportCachedRuleViolations(ctx); - } else { - processSourceCodeWithoutCache(sourceCode, ruleSets, ctx); - } - } - } - - private boolean isCacheUpToDate(final RuleContext ctx) { - return configuration.getAnalysisCache().isUpToDate(ctx.getSourceCodeFile()); - } - - private void reportCachedRuleViolations(final RuleContext ctx) { - for (final RuleViolation rv : configuration.getAnalysisCache().getCachedViolations(ctx.getSourceCodeFile())) { - ctx.getReport().addRuleViolation(rv); - } - } - - private void processSourceCodeWithoutCache(final Reader sourceCode, final RuleSets ruleSets, final RuleContext ctx) throws PMDException { - try { - ruleSets.start(ctx); - processSource(sourceCode, ruleSets, ctx); - } catch (ParseException pe) { - configuration.getAnalysisCache().analysisFailed(ctx.getSourceCodeFile()); - throw new PMDException("Error while parsing " + ctx.getSourceCodeFile(), pe); - } catch (Exception e) { - configuration.getAnalysisCache().analysisFailed(ctx.getSourceCodeFile()); - throw new PMDException("Error while processing " + ctx.getSourceCodeFile(), e); - } finally { - ruleSets.end(ctx); - } - } - - private Node parse(RuleContext ctx, Reader sourceCode, Parser parser) { - try (TimedOperation to = TimeTracker.startOperation(TimedOperationCategory.PARSER)) { - return parser.parse(String.valueOf(ctx.getSourceCodeFile()), sourceCode); - } - } - - - - private void processSource(Reader sourceCode, RuleSets ruleSets, RuleContext ctx) { - - // basically: - // 1. make the union of all stage dependencies of each rule, by language, for the Rulesets - // 2. order them by dependency - // 3. run them and time them if needed - - // The problem is the first two steps need only be done once. - // They're probably costly and if we do this here without changing anything, - // they'll be done on each file! Btw currently the "usesDfa" and such are nested loops testing - // all rules of all rulesets, but they're run on each file too! - - // FIXME - this implementation is a hack to wire-in stages without - // needing to change RuleSet immediately - - // With mutable RuleSets, caching of the value can't be guaranteed to be accurate... - // The approach I'd like to take is either - // * to create a new RunnableRulesets class which is immutable, and performs all these preliminary - // computations upon construction. - // * or to modify Ruleset and Rulesets to be immutable. This IMO is a better option because it makes - // these objects easier to reason about and pass around from thread to thread. It also avoid creating - // a new class, and breaking SourceCodeProcessor's API too much. - // - // The "preliminary computations" also include: - // * removing dysfunctional rules - // * separating rulechain rules from normal rules - // * grouping rules by language/ file extension - // * etc. - - LanguageVersion languageVersion = ctx.getLanguageVersion(); - - Parser parser = PMD.parserFor(languageVersion, configuration); - - RootNode rootNode = (RootNode) parse(ctx, sourceCode, parser); - - dependencyHelper.runLanguageSpecificStages(ruleSets, languageVersion, rootNode); - - ruleSets.apply(Collections.singletonList(rootNode), ctx); - } - - - - - private void determineLanguage(RuleContext ctx) { - // If LanguageVersion of the source file is not known, make a - // determination - if (ctx.getLanguageVersion() == null) { - LanguageVersion languageVersion = configuration.getLanguageVersionOfFile(ctx.getSourceCodeFilename()); - ctx.setLanguageVersion(languageVersion); - } - } -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/internal/RulesetStageDependencyHelper.java b/pmd-core/src/main/java/net/sourceforge/pmd/internal/RulesetStageDependencyHelper.java index 5eccfd32b2..4770879465 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/internal/RulesetStageDependencyHelper.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/internal/RulesetStageDependencyHelper.java @@ -15,7 +15,6 @@ import java.util.concurrent.ConcurrentHashMap; import net.sourceforge.pmd.PMDConfiguration; import net.sourceforge.pmd.Rule; import net.sourceforge.pmd.RuleSets; -import net.sourceforge.pmd.SourceCodeProcessor; import net.sourceforge.pmd.benchmark.TimeTracker; import net.sourceforge.pmd.benchmark.TimedOperation; import net.sourceforge.pmd.benchmark.TimedOperationCategory; @@ -25,8 +24,6 @@ import net.sourceforge.pmd.lang.ast.AstProcessingStage; import net.sourceforge.pmd.lang.ast.RootNode; /** - * Temporary helper for {@link SourceCodeProcessor} until we change rulesets. - * See comment in SourceCodeProcessor. * * @author Clément Fournier */ diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/AbstractParser.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/AbstractParser.java deleted file mode 100644 index e1057c9522..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/AbstractParser.java +++ /dev/null @@ -1,27 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang; - -/** - * This is a generic implementation of the Parser interface. - * - * @see Parser - * - * @deprecated This will become useless in PMD 7. Implement or use {@link Parser} directly - */ -@Deprecated -public abstract class AbstractParser implements Parser { - protected final ParserOptions parserOptions; - - public AbstractParser(ParserOptions parserOptions) { - this.parserOptions = parserOptions; - } - - @Override - public ParserOptions getParserOptions() { - return parserOptions; - } - -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/LanguageVersionHandler.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/LanguageVersionHandler.java index 16b0e724ae..8d43032984 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/LanguageVersionHandler.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/LanguageVersionHandler.java @@ -63,6 +63,11 @@ public interface LanguageVersionHandler { Parser getParser(ParserOptions parserOptions); + default Parser getParser() { + return getParser(getDefaultParserOptions()); + } + + /** * Get the RuleViolationFactory. */ diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/Parser.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/Parser.java index 1b9574e687..f1b964bc4f 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/Parser.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/Parser.java @@ -4,10 +4,10 @@ package net.sourceforge.pmd.lang; -import java.io.Reader; - -import net.sourceforge.pmd.lang.ast.ParseException; +import net.sourceforge.pmd.PMD; +import net.sourceforge.pmd.lang.ast.FileAnalysisException; import net.sourceforge.pmd.lang.ast.RootNode; +import net.sourceforge.pmd.lang.ast.SemanticErrorReporter; /** * Produces an AST from a source file. Instances of this interface must @@ -22,28 +22,78 @@ import net.sourceforge.pmd.lang.ast.RootNode; */ public interface Parser { + /** - * Get the ParserOptions used by this Parser. + * Parses an entire tree for this language. This may perform some + * semantic analysis, like name resolution. * - * @deprecated Parser options should be a parameter to {@link #parse(String, Reader)} + * @param task Description of the parsing task + * + * @return The root of the tree corresponding to the source code. + * + * @throws IllegalArgumentException If the language version of the + * parsing task is for an incorrect language + * @throws FileAnalysisException If any error occurs */ - @Deprecated - ParserOptions getParserOptions(); + RootNode parse(ParserTask task) throws FileAnalysisException; /** - * Parse source code and return the root node of the AST. - * - * @param fileName - * The file name being parsed (may be null). - * @param source - * Reader that provides the source code of a compilation unit - * @return the root node of the AST that is built from the source code - * @throws ParseException - * In case the source code could not be parsed, probably due to - * syntactical errors. + * Parameters passed to a parsing task. */ - RootNode parse(String fileName, Reader source) throws ParseException; + final class ParserTask { + + private final LanguageVersion lv; + private final String filepath; + private final String sourceText; + private final SemanticErrorReporter reporter; + + private final String commentMarker; + + + public ParserTask(LanguageVersion lv, String filepath, String sourceText, SemanticErrorReporter reporter) { + this(lv, filepath, sourceText, reporter, PMD.SUPPRESS_MARKER); + } + + public ParserTask(LanguageVersion lv, String filepath, String sourceText, SemanticErrorReporter reporter, String commentMarker) { + this.lv = lv; + this.filepath = filepath; + this.sourceText = sourceText; + this.reporter = reporter; + this.commentMarker = commentMarker; + } + + + public LanguageVersion getLanguageVersion() { + return lv; + } + + /** + * The display name for where the file comes from. This should + * not be interpreted, it may not be a file-system path. + */ + public String getFileDisplayName() { + return filepath; + } + + /** + * The full text of the file to parse. + */ + public String getSourceText() { + return sourceText; + } + + /** + * The error reporter for semantic checks. + */ + public SemanticErrorReporter getReporter() { + return reporter; + } + + public String getCommentMarker() { + return commentMarker; + } + } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/FileAnalysisException.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/FileAnalysisException.java new file mode 100644 index 0000000000..b9781a938d --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/FileAnalysisException.java @@ -0,0 +1,33 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ast; + +/** + * An exception that occurs while processing a file. Subtypes include + *
    + *
  • {@link TokenMgrError}: lexical syntax errors + *
  • {@link ParseException}: syntax errors + *
  • {@link SemanticException}: exceptions occurring after the parsing + * phase, because the source code is semantically invalid + *
+ */ +public class FileAnalysisException extends RuntimeException { + + public FileAnalysisException() { + super(); + } + + public FileAnalysisException(String message) { + super(message); + } + + public FileAnalysisException(Throwable cause) { + super(cause); + } + public FileAnalysisException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/ParseException.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/ParseException.java index eba75320d6..00672d0117 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/ParseException.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/ParseException.java @@ -15,7 +15,7 @@ import net.sourceforge.pmd.lang.ast.impl.javacc.JavaccToken; import net.sourceforge.pmd.lang.ast.impl.javacc.JavaccTokenDocument; import net.sourceforge.pmd.util.StringUtil; -public class ParseException extends RuntimeException { +public class ParseException extends FileAnalysisException { /** * This is the last token that has been consumed successfully. If 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 new file mode 100644 index 0000000000..dfb163895a --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/SemanticErrorReporter.java @@ -0,0 +1,68 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ast; + +import java.text.MessageFormat; + +/** + * Reports errors that occur after parsing. This may be used to implement + * semantic checks in a language specific way. + */ +public interface SemanticErrorReporter { + // TODO use resource bundle keys instead of string messages. + + + /** + * Report a warning at the given location. Warnings do not abort + * the analysis. + * + * @param location Location where the warning should be reported + * @param message Message (rendered using a {@link MessageFormat}) + * @param formatArgs Format arguments + */ + void warn(Node location, String message, Object... formatArgs); + + + /** + * Report an error at the given location. Errors abort subsequent analysis. + * The produced error can be thrown by the caller. + * + * @param location Location where the error should be reported + * @param message Message (rendered using a {@link MessageFormat}) + * @param formatArgs Format arguments + */ + SemanticException error(Node location, String message, Object... formatArgs); + + + /** + * Returns true if at least one error has been reported. + */ + boolean hasError(); + + static SemanticErrorReporter noop() { + return new SemanticErrorReporter() { + + private boolean hasError = false; + + @Override + public void warn(Node location, String message, Object... formatArgs) { + // noop + } + + @Override + public SemanticException error(Node location, String message, Object... formatArgs) { + hasError = true; + return new SemanticException(MessageFormat.format(message, formatArgs)); + } + + @Override + public boolean hasError() { + return hasError; + } + }; + } + + +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/SemanticException.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/SemanticException.java new file mode 100644 index 0000000000..a5de8e298d --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/SemanticException.java @@ -0,0 +1,26 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ast; + +/** + * An error that occurs after validating a file. + */ +public class SemanticException extends FileAnalysisException { + + public SemanticException() { + super(); + } + + public SemanticException(String message) { + super(message); + } + + public SemanticException(Throwable cause) { + super(cause); + } + public SemanticException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/TokenMgrError.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/TokenMgrError.java index 477b8de445..65e135a055 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/TokenMgrError.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/TokenMgrError.java @@ -12,7 +12,7 @@ import net.sourceforge.pmd.util.StringUtil; /** * An error thrown during lexical analysis of a file. */ -public final class TokenMgrError extends RuntimeException { +public final class TokenMgrError extends FileAnalysisException { private final int line; private final int column; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/AntlrBaseParser.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/AntlrBaseParser.java index 0e84059e63..25e30602f3 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/AntlrBaseParser.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/AntlrBaseParser.java @@ -4,9 +4,6 @@ package net.sourceforge.pmd.lang.ast.impl.antlr4; -import java.io.IOException; -import java.io.Reader; - import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.Lexer; @@ -35,18 +32,8 @@ public abstract class AntlrBaseParser< } @Override - public ParserOptions getParserOptions() { - return parserOptions; - } - - @Override - public R parse(final String fileName, final Reader source) throws ParseException { - CharStream cs; - try { - cs = CharStreams.fromReader(source, fileName); - } catch (final IOException e) { - throw new ParseException(e); - } + public R parse(ParserTask task) throws ParseException { + CharStream cs = CharStreams.fromString(task.getSourceText(), task.getFileDisplayName()); return parse(getLexer(cs)); } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/javacc/JjtreeParserAdapter.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/javacc/JjtreeParserAdapter.java index 054b6a621e..b9ce1dcda6 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/javacc/JjtreeParserAdapter.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/javacc/JjtreeParserAdapter.java @@ -4,10 +4,7 @@ package net.sourceforge.pmd.lang.ast.impl.javacc; -import java.io.Reader; - import net.sourceforge.pmd.lang.Parser; -import net.sourceforge.pmd.lang.ParserOptions; import net.sourceforge.pmd.lang.ast.CharStream; import net.sourceforge.pmd.lang.ast.ParseException; import net.sourceforge.pmd.lang.ast.RootNode; @@ -22,15 +19,7 @@ import net.sourceforge.pmd.lang.ast.TokenMgrError; */ public abstract class JjtreeParserAdapter implements Parser { - protected final ParserOptions parserOptions; - - protected JjtreeParserAdapter(ParserOptions parserOptions) { - this.parserOptions = parserOptions; - } - - @Override - public ParserOptions getParserOptions() { - return parserOptions; + protected JjtreeParserAdapter() { } protected abstract JavaccTokenDocument newDocument(String fullText); @@ -40,19 +29,18 @@ public abstract class JjtreeParserAdapter implements Parser } @Override - public R parse(String fileName, Reader source) throws ParseException { - String text = CharStreamFactory.toString(source); - JavaccTokenDocument doc = newDocument(text); + public R parse(ParserTask task) throws ParseException { + JavaccTokenDocument doc = newDocument(task.getSourceText()); CharStream charStream = newCharStream(doc); try { - return parseImpl(charStream, getParserOptions()); + return parseImpl(charStream, task.getCommentMarker()); } catch (TokenMgrError tme) { - throw tme.withFileName(fileName); + throw tme.withFileName(task.getFileDisplayName()); } } - protected abstract R parseImpl(CharStream cs, ParserOptions options) throws ParseException; + protected abstract R parseImpl(CharStream cs, String suppressMarker) throws ParseException; @Override diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/processor/AbstractPMDProcessor.java b/pmd-core/src/main/java/net/sourceforge/pmd/processor/AbstractPMDProcessor.java index 07552dd3e8..6bbcf8cb5f 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/processor/AbstractPMDProcessor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/processor/AbstractPMDProcessor.java @@ -5,22 +5,14 @@ package net.sourceforge.pmd.processor; import java.io.IOException; -import java.util.HashSet; import java.util.List; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; import org.apache.commons.io.IOUtils; import net.sourceforge.pmd.PMDConfiguration; import net.sourceforge.pmd.Report; -import net.sourceforge.pmd.Rule; import net.sourceforge.pmd.RuleContext; -import net.sourceforge.pmd.RuleSetFactory; import net.sourceforge.pmd.RuleSets; -import net.sourceforge.pmd.RulesetsFactoryUtils; -import net.sourceforge.pmd.SourceCodeProcessor; import net.sourceforge.pmd.benchmark.TimeTracker; import net.sourceforge.pmd.benchmark.TimedOperation; import net.sourceforge.pmd.benchmark.TimedOperationCategory; @@ -33,15 +25,13 @@ import net.sourceforge.pmd.util.datasource.DataSource; */ public abstract class AbstractPMDProcessor { - private static final Logger LOG = Logger.getLogger(AbstractPMDProcessor.class.getName()); - protected final PMDConfiguration configuration; - public AbstractPMDProcessor(PMDConfiguration configuration) { + AbstractPMDProcessor(PMDConfiguration configuration) { this.configuration = configuration; } - public void renderReports(final List renderers, final Report report) { + protected void renderReports(final List renderers, final Report report) { try (TimedOperation to = TimeTracker.startOperation(TimedOperationCategory.REPORTING)) { for (Renderer r : renderers) { @@ -52,74 +42,13 @@ public abstract class AbstractPMDProcessor { } } - /** - * - * @deprecated this method will be removed. It was once used to determine a short filename - * for the file being analyzed, so that shortnames can be reported. But the logic has - * been moved to the renderers. - */ - @Deprecated - protected String filenameFrom(DataSource dataSource) { - return dataSource.getNiceFileName(configuration.isReportShortNames(), configuration.getInputPaths()); - } - - /** - * Create instances for each rule defined in the ruleset(s) in the - * configuration. Please note, that the returned instances must - * not be used by different threads. Each thread must create its - * own copy of the rules. - * - * @param factory The factory used to create the configured rule sets - * @param report The base report on which to report any configuration errors - * @return the rules within a rulesets - */ - protected RuleSets createRuleSets(RuleSetFactory factory, Report report) { - final RuleSets rs = RulesetsFactoryUtils.getRuleSets(configuration.getRuleSets(), factory); - - final Set brokenRules = removeBrokenRules(rs); - for (final Rule rule : brokenRules) { - report.addConfigError(new Report.ConfigurationError(rule, rule.dysfunctionReason())); - } - - return rs; - } - - /** - * Remove and return the misconfigured rules from the rulesets and log them - * for good measure. - * - * @param ruleSets RuleSets to prune of broken rules. - * @return Set - */ - private Set removeBrokenRules(final RuleSets ruleSets) { - final Set brokenRules = new HashSet<>(); - ruleSets.removeDysfunctionalRules(brokenRules); - - for (final Rule rule : brokenRules) { - if (LOG.isLoggable(Level.WARNING)) { - LOG.log(Level.WARNING, - "Removed misconfigured rule: " + rule.getName() + " cause: " + rule.dysfunctionReason()); - } - } - - return brokenRules; - } - @SuppressWarnings("PMD.CloseResource") - // the data sources must only be closed after the threads are finished - // this is done manually without a try-with-resources - public void processFiles(RuleSetFactory ruleSetFactory, List files, RuleContext ctx, - List renderers) { + public void processFiles(RuleSets rulesets, List files, RuleContext ctx, List renderers) { + // the data sources must only be closed after the threads are finished + // this is done manually without a try-with-resources try { - final RuleSets rs = createRuleSets(ruleSetFactory, ctx.getReport()); - configuration.getAnalysisCache().checkValidity(rs, configuration.getClassLoader()); - final SourceCodeProcessor processor = new SourceCodeProcessor(configuration); - for (final DataSource dataSource : files) { - // this is the real, canonical and absolute filename (not shortened) - String realFileName = dataSource.getNiceFileName(false, null); - - runAnalysis(new PmdRunnable(dataSource, realFileName, renderers, ctx, rs, processor)); + runAnalysis(new PmdRunnable(dataSource, renderers, ctx, rulesets, configuration)); } // render base report first - general errors @@ -139,4 +68,13 @@ public abstract class AbstractPMDProcessor { protected abstract void runAnalysis(PmdRunnable runnable); protected abstract void collectReports(List renderers); + + /** + * Returns a new file processor. The strategy used for threading is + * determined by {@link PMDConfiguration#getThreads()}. + */ + public static AbstractPMDProcessor newFileProcessor(final PMDConfiguration configuration) { + return configuration.getThreads() > 0 ? new MultiThreadProcessor(configuration) + : new MonoThreadProcessor(configuration); + } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/processor/MonoThreadProcessor.java b/pmd-core/src/main/java/net/sourceforge/pmd/processor/MonoThreadProcessor.java index 6acf61a32c..c1d490135c 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/processor/MonoThreadProcessor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/processor/MonoThreadProcessor.java @@ -15,7 +15,7 @@ import net.sourceforge.pmd.renderers.Renderer; * @author Romain Pelisse <belaran@gmail.com> * */ -public final class MonoThreadProcessor extends AbstractPMDProcessor { +final class MonoThreadProcessor extends AbstractPMDProcessor { private final List reports = new ArrayList<>(); diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/processor/MultiThreadProcessor.java b/pmd-core/src/main/java/net/sourceforge/pmd/processor/MultiThreadProcessor.java index f398a90db8..d3633ff9c0 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/processor/MultiThreadProcessor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/processor/MultiThreadProcessor.java @@ -19,7 +19,7 @@ import net.sourceforge.pmd.renderers.Renderer; /** * @author Romain Pelisse <belaran@gmail.com> */ -public class MultiThreadProcessor extends AbstractPMDProcessor { +final class MultiThreadProcessor extends AbstractPMDProcessor { private final ExecutorService executor; private final CompletionService completionService; 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 d3ddeb6230..63aae77f1b 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 @@ -4,20 +4,33 @@ package net.sourceforge.pmd.processor; -import java.io.BufferedInputStream; +import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.util.Collections; import java.util.List; import java.util.concurrent.Callable; import java.util.logging.Level; import java.util.logging.Logger; -import net.sourceforge.pmd.PMDException; +import org.apache.commons.io.IOUtils; + +import net.sourceforge.pmd.PMDConfiguration; import net.sourceforge.pmd.Report; import net.sourceforge.pmd.RuleContext; +import net.sourceforge.pmd.RuleSet; import net.sourceforge.pmd.RuleSets; -import net.sourceforge.pmd.SourceCodeProcessor; +import net.sourceforge.pmd.RuleViolation; import net.sourceforge.pmd.benchmark.TimeTracker; +import net.sourceforge.pmd.benchmark.TimedOperation; +import net.sourceforge.pmd.benchmark.TimedOperationCategory; +import net.sourceforge.pmd.internal.RulesetStageDependencyHelper; +import net.sourceforge.pmd.lang.LanguageVersion; +import net.sourceforge.pmd.lang.Parser; +import net.sourceforge.pmd.lang.Parser.ParserTask; +import net.sourceforge.pmd.lang.ast.FileAnalysisException; +import net.sourceforge.pmd.lang.ast.RootNode; +import net.sourceforge.pmd.lang.ast.SemanticErrorReporter; import net.sourceforge.pmd.renderers.Renderer; import net.sourceforge.pmd.util.datasource.DataSource; @@ -28,32 +41,43 @@ public class PmdRunnable implements Callable { private static final ThreadLocal LOCAL_THREAD_CONTEXT = new ThreadLocal<>(); private final DataSource dataSource; - private final String fileName; + private final File file; private final List renderers; private final RuleContext ruleContext; private final RuleSets ruleSets; - private final SourceCodeProcessor sourceCodeProcessor; + private final PMDConfiguration configuration; - public PmdRunnable(DataSource dataSource, String fileName, List renderers, - RuleContext ruleContext, RuleSets ruleSets, SourceCodeProcessor sourceCodeProcessor) { + private final RulesetStageDependencyHelper dependencyHelper; + + public PmdRunnable(DataSource dataSource, + List renderers, + RuleContext ruleContext, + List ruleSets, + PMDConfiguration configuration) { + this(dataSource, renderers, ruleContext, new RuleSets(ruleSets), configuration); + } + + public PmdRunnable(DataSource dataSource, + List renderers, + RuleContext ruleContext, + RuleSets ruleSets, + PMDConfiguration configuration) { this.ruleSets = ruleSets; this.dataSource = dataSource; - this.fileName = fileName; + // this is the real, canonical and absolute filename (not shortened) + String realFileName = dataSource.getNiceFileName(false, null); + + this.file = new File(realFileName); this.renderers = renderers; this.ruleContext = ruleContext; - this.sourceCodeProcessor = sourceCodeProcessor; + this.configuration = configuration; + this.dependencyHelper = new RulesetStageDependencyHelper(configuration); } public static void reset() { LOCAL_THREAD_CONTEXT.remove(); } - private void addError(Report report, Exception e, String errorMessage) { - // unexpected exception: log and stop executor service - LOG.log(Level.FINE, errorMessage, e); - report.addError(new Report.ProcessingError(e, fileName)); - } - @Override public Report call() { TimeTracker.initThread(); @@ -63,25 +87,48 @@ public class PmdRunnable implements Callable { tc = new ThreadContext(new RuleSets(ruleSets), new RuleContext(ruleContext)); LOCAL_THREAD_CONTEXT.set(tc); } + RuleContext ruleCtx = tc.ruleContext; + LanguageVersion langVersion = + ruleContext.getLanguageVersion() != null ? ruleCtx.getLanguageVersion() + : configuration.getLanguageVersionOfFile(file.getPath()); - Report report = Report.createReport(tc.ruleContext, fileName); + Report report = new Report(); + // overtake the listener + report.addListeners(ruleCtx.getReport().getListeners()); + ruleCtx.setReport(report); + ruleCtx.setSourceCodeFile(file); + ruleCtx.setLanguageVersion(langVersion); if (LOG.isLoggable(Level.FINE)) { - LOG.fine("Processing " + fileName); + LOG.fine("Processing " + file); } + for (Renderer r : renderers) { r.startFileAnalysis(dataSource); } - try (InputStream stream = new BufferedInputStream(dataSource.getInputStream())) { - tc.ruleContext.setLanguageVersion(null); - sourceCodeProcessor.processSourceCode(stream, tc.ruleSets, tc.ruleContext); - } catch (PMDException pmde) { - addError(report, pmde, "Error while processing file: " + fileName); - } catch (IOException ioe) { - addError(report, ioe, "IOException during processing of " + fileName); - } catch (RuntimeException re) { - addError(report, re, "RuntimeException during processing of " + fileName); + + // Coarse check to see if any RuleSet applies to file, will need to do a finer RuleSet specific check later + if (ruleSets.applies(file)) { + if (configuration.getAnalysisCache().isUpToDate(file)) { + reportCachedRuleViolations(ruleCtx); + } else { + try { + processSource(ruleCtx, langVersion); + } catch (Exception e) { + configuration.getAnalysisCache().analysisFailed(file); + report.addError(new Report.ProcessingError(e, file.getPath())); + + if (ruleCtx.isIgnoreExceptions()) { + LOG.log(Level.FINE, "Exception while processing file: " + file, e); + } else { + if (e instanceof FileAnalysisException) { + throw (FileAnalysisException) e; + } + throw new FileAnalysisException(e); + } + } + } } TimeTracker.finishThread(); @@ -89,7 +136,59 @@ public class PmdRunnable implements Callable { return report; } + public void processSource(RuleContext ruleCtx, LanguageVersion languageVersion) throws IOException, FileAnalysisException { + String fullSource; + try (InputStream stream = dataSource.getInputStream()) { + fullSource = IOUtils.toString(stream, configuration.getSourceEncoding()); + } + + try { + ruleSets.start(ruleCtx); + processSource(fullSource, ruleSets, ruleCtx, languageVersion); + } finally { + ruleSets.end(ruleCtx); + } + + } + + + private void reportCachedRuleViolations(final RuleContext ctx) { + for (final RuleViolation rv : configuration.getAnalysisCache().getCachedViolations(ctx.getSourceCodeFile())) { + ctx.getReport().addRuleViolation(rv); + } + } + + private RootNode parse(Parser parser, ParserTask task) throws IOException { + try (TimedOperation to = TimeTracker.startOperation(TimedOperationCategory.PARSER)) { + return parser.parse(task); + } + } + + + private void processSource(String sourceCode, + RuleSets ruleSets, + RuleContext ctx, + LanguageVersion languageVersion) throws FileAnalysisException, IOException { + + ParserTask task = new ParserTask( + languageVersion, + String.valueOf(ctx.getSourceCodeFile()), + sourceCode, + SemanticErrorReporter.noop(), + configuration.getSuppressMarker() + ); + + Parser parser = languageVersion.getLanguageVersionHandler().getParser(); + + RootNode rootNode = parse(parser, task); + + dependencyHelper.runLanguageSpecificStages(ruleSets, languageVersion, rootNode); + + ruleSets.apply(Collections.singletonList(rootNode), ctx); + } + private static class ThreadContext { + /* default */ final RuleSets ruleSets; /* default */ final RuleContext ruleContext; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/processor/PmdThreadFactory.java b/pmd-core/src/main/java/net/sourceforge/pmd/processor/PmdThreadFactory.java index 51c84b3063..e198c20a3c 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/processor/PmdThreadFactory.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/processor/PmdThreadFactory.java @@ -7,7 +7,7 @@ package net.sourceforge.pmd.processor; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicInteger; -public class PmdThreadFactory implements ThreadFactory { +class PmdThreadFactory implements ThreadFactory { private final AtomicInteger counter = new AtomicInteger(); 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 914f6c73bc..74763aa739 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 @@ -7,6 +7,7 @@ package net.sourceforge.pmd.util.datasource; import java.io.Closeable; import java.io.IOException; import java.io.InputStream; +import java.io.StringReader; /** * Represents a source file to be analyzed. Different implementations can get @@ -33,4 +34,10 @@ public interface DataSource extends Closeable { * @return String */ String getNiceFileName(boolean shortNames, String inputFileName); + + + static DataSource forString(String sourceText, String fileName) { + return new ReaderDataSource(new StringReader(sourceText), fileName); + } + } 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 0ae6fad1db..fcea03e8c0 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 @@ -18,6 +18,7 @@ import java.util.Scanner; import java.util.logging.Level; import java.util.logging.Logger; +import org.apache.commons.io.IOUtils; import org.apache.commons.io.input.CloseShieldInputStream; import org.apache.commons.lang3.StringEscapeUtils; @@ -27,8 +28,10 @@ import net.sourceforge.pmd.lang.LanguageRegistry; import net.sourceforge.pmd.lang.LanguageVersion; import net.sourceforge.pmd.lang.LanguageVersionHandler; import net.sourceforge.pmd.lang.Parser; +import net.sourceforge.pmd.lang.Parser.ParserTask; import net.sourceforge.pmd.lang.ast.AstAnalysisContext; import net.sourceforge.pmd.lang.ast.RootNode; +import net.sourceforge.pmd.lang.ast.SemanticErrorReporter; import net.sourceforge.pmd.lang.rule.xpath.Attribute; import net.sourceforge.pmd.properties.PropertyDescriptor; import net.sourceforge.pmd.properties.PropertySource; @@ -159,24 +162,28 @@ public class TreeExportCli { LanguageVersion langVersion = LanguageRegistry.findLanguageByTerseName(language).getDefaultVersion(); LanguageVersionHandler languageHandler = langVersion.getLanguageVersionHandler(); - Parser parser = languageHandler.getParser(languageHandler.getDefaultParserOptions()); + Parser parser = languageHandler.getParser(); @SuppressWarnings("PMD.CloseResource") - Reader source; + final Reader source; + final String filename; if (file == null && !readStdin) { throw bail("One of --file or --read-stdin must be mentioned"); } else if (readStdin) { System.err.println("Reading from stdin..."); source = new StringReader(readFromSystemIn()); + filename = "stdin"; } else { source = Files.newBufferedReader(new File(file).toPath(), Charset.forName(encoding)); + filename = file; } // disable warnings for deprecated attributes Logger.getLogger(Attribute.class.getName()).setLevel(Level.OFF); - try (Reader reader = source) { - RootNode root = (RootNode) parser.parse(file, reader); + try { + String fullSource = IOUtils.toString(source); + RootNode root = parser.parse(new ParserTask(langVersion, filename, fullSource, SemanticErrorReporter.noop())); AstAnalysisContext ctx = new AstAnalysisContext() { @Override @@ -193,6 +200,8 @@ public class TreeExportCli { languageHandler.getProcessingStages().forEach(it -> it.processAST(root, ctx)); renderer.renderSubtree(root, System.out); + } finally { + source.close(); } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/internal/StageDependencyTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/internal/StageDependencyTest.java index aa8760c33b..26ee2eeef1 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/internal/StageDependencyTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/internal/StageDependencyTest.java @@ -4,7 +4,6 @@ package net.sourceforge.pmd.internal; -import java.io.StringReader; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -12,7 +11,6 @@ import java.util.List; import org.junit.Assert; import org.junit.Test; -import net.sourceforge.pmd.PMD; import net.sourceforge.pmd.PMDConfiguration; import net.sourceforge.pmd.PMDException; import net.sourceforge.pmd.Rule; @@ -24,11 +22,13 @@ import net.sourceforge.pmd.lang.Language; import net.sourceforge.pmd.lang.LanguageRegistry; import net.sourceforge.pmd.lang.LanguageVersion; import net.sourceforge.pmd.lang.Parser; +import net.sourceforge.pmd.lang.Parser.ParserTask; import net.sourceforge.pmd.lang.ast.AstProcessingStage; import net.sourceforge.pmd.lang.ast.DummyAstStages; import net.sourceforge.pmd.lang.ast.DummyNode; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.ast.RootNode; +import net.sourceforge.pmd.lang.ast.SemanticErrorReporter; import net.sourceforge.pmd.lang.rule.AbstractRule; public class StageDependencyTest { @@ -36,19 +36,18 @@ public class StageDependencyTest { private final LanguageVersion version = LanguageRegistry.findLanguageByTerseName("dummy").getVersion("1.0"); private DummyNode process(String source, RuleSets ruleSets) { - PMDConfiguration configuration = new PMDConfiguration(); - return process(source, ruleSets, new RulesetStageDependencyHelper(configuration), configuration); + return process(source, ruleSets, new RulesetStageDependencyHelper(new PMDConfiguration())); } - private DummyNode process(String source, RuleSets ruleSets, RulesetStageDependencyHelper helper, PMDConfiguration configuration) { + private DummyNode process(String source, RuleSets ruleSets, RulesetStageDependencyHelper helper) { - RuleContext context = new RuleContext(); + // TODO Handle Rules having different parser options. + Parser parser = version.getLanguageVersionHandler().getParser(); - Parser parser = PMD.parserFor(version, configuration); - context.setLanguageVersion(version); + ParserTask task = new ParserTask(version, "dummyfile.dummy", source, SemanticErrorReporter.noop()); - RootNode rootNode = (RootNode) parser.parse("dummyfile.dummy", new StringReader(source)); + RootNode rootNode = parser.parse(task); helper.runLanguageSpecificStages(ruleSets, version, rootNode); 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 8985e8a644..f78e5b0e6b 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 @@ -4,8 +4,6 @@ package net.sourceforge.pmd.lang; -import java.io.Reader; - import net.sourceforge.pmd.Rule; import net.sourceforge.pmd.RuleContext; import net.sourceforge.pmd.RuleViolation; @@ -50,15 +48,11 @@ public class DummyLanguageModule extends BaseLanguageModule { @Override public Parser getParser(ParserOptions parserOptions) { - return new AbstractParser(parserOptions) { - @Override - public DummyRoot parse(String fileName, Reader source) throws ParseException { - DummyRoot node = new DummyRoot(); - node.setCoords(1, 1, 2, 10); - node.setImage("Foo"); - return node; - } - + return task -> { + DummyRoot node = new DummyRoot(); + node.setCoords(1, 1, 2, 10); + node.setImage("Foo"); + return node; }; } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/processor/MultiThreadProcessorTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/processor/MultiThreadProcessorTest.java index e0a1025e8d..6fff6bb7ae 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/processor/MultiThreadProcessorTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/processor/MultiThreadProcessorTest.java @@ -21,7 +21,8 @@ import net.sourceforge.pmd.PMDConfiguration; import net.sourceforge.pmd.Report; import net.sourceforge.pmd.Report.ConfigurationError; import net.sourceforge.pmd.RuleContext; -import net.sourceforge.pmd.RuleSetFactory; +import net.sourceforge.pmd.RuleSetNotFoundException; +import net.sourceforge.pmd.RuleSets; import net.sourceforge.pmd.RuleViolation; import net.sourceforge.pmd.RulesetsFactoryUtils; import net.sourceforge.pmd.ThreadSafeReportListener; @@ -36,13 +37,11 @@ public class MultiThreadProcessorTest { private RuleContext ctx; private MultiThreadProcessor processor; - private RuleSetFactory ruleSetFactory; private List files; private SimpleReportListener reportListener; - public void setUpForTest(final String ruleset) { + public RuleSets setUpForTest(final String ruleset) throws RuleSetNotFoundException { PMDConfiguration configuration = new PMDConfiguration(); - configuration.setRuleSets(ruleset); configuration.setThreads(2); files = new ArrayList<>(); files.add(new StringDataSource("file1-violation.dummy", "ABC")); @@ -53,15 +52,15 @@ public class MultiThreadProcessorTest { ctx.getReport().addListener(reportListener); processor = new MultiThreadProcessor(configuration); - ruleSetFactory = RulesetsFactoryUtils.defaultFactory(); + return RulesetsFactoryUtils.defaultFactory().createRuleSets(ruleset); } @Test - public void testRulesDysnfunctionalLog() throws IOException { - setUpForTest("rulesets/MultiThreadProcessorTest/dysfunctional.xml"); + public void testRulesDysnfunctionalLog() throws Exception { + RuleSets ruleSets = setUpForTest("rulesets/MultiThreadProcessorTest/dysfunctional.xml"); final SimpleRenderer renderer = new SimpleRenderer(null, null); renderer.start(); - processor.processFiles(ruleSetFactory, files, ctx, Collections.singletonList(renderer)); + processor.processFiles(ruleSets, files, ctx, Collections.singletonList(renderer)); renderer.end(); final Iterator configErrors = renderer.getReport().getConfigurationErrors().iterator(); @@ -75,9 +74,9 @@ public class MultiThreadProcessorTest { } @Test - public void testRulesThreadSafety() { - setUpForTest("rulesets/MultiThreadProcessorTest/basic.xml"); - processor.processFiles(ruleSetFactory, files, ctx, Collections.emptyList()); + public void testRulesThreadSafety() throws RuleSetNotFoundException { + RuleSets ruleSets = setUpForTest("rulesets/MultiThreadProcessorTest/basic.xml"); + processor.processFiles(ruleSets, files, ctx, Collections.emptyList()); // if the rule is not executed, then maybe a // ConcurrentModificationException happened diff --git a/pmd-java/pom.xml b/pmd-java/pom.xml index 41b1950234..2ea66cba5b 100644 --- a/pmd-java/pom.xml +++ b/pmd-java/pom.xml @@ -196,6 +196,12 @@ kotest-runner-junit5-jvm test + + io.kotlintest + kotlintest-runner-junit5 + 3.1.8 + test + com.google.guava guava 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 afce58d173..69ad05bc3d 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 @@ -4,7 +4,6 @@ package net.sourceforge.pmd.lang.java.ast; -import net.sourceforge.pmd.lang.ParserOptions; import net.sourceforge.pmd.lang.ast.CharStream; import net.sourceforge.pmd.lang.ast.ParseException; import net.sourceforge.pmd.lang.ast.impl.javacc.JavaCharStream; @@ -22,8 +21,7 @@ public class JavaParser extends JjtreeParserAdapter { private final LanguageLevelChecker checker; - public JavaParser(LanguageLevelChecker checker, ParserOptions parserOptions) { - super(parserOptions); + public JavaParser(LanguageLevelChecker checker) { this.checker = checker; } @@ -39,9 +37,8 @@ public class JavaParser extends JjtreeParserAdapter { } @Override - protected ASTCompilationUnit parseImpl(CharStream cs, ParserOptions options) throws ParseException { + protected ASTCompilationUnit parseImpl(CharStream cs, String suppressMarker) throws ParseException { JavaParserImpl parser = new JavaParserImpl(cs); - String suppressMarker = options.getSuppressMarker(); if (suppressMarker != null) { parser.setSuppressMarker(suppressMarker); } 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 1691a7c738..35abbbcbd9 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 @@ -53,7 +53,7 @@ public class JavaLanguageHandler extends AbstractPmdLanguageVersionHandler { @Override public Parser getParser(ParserOptions parserOptions) { - return new JavaParser(levelChecker, parserOptions); + return new JavaParser(levelChecker); } @Override diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/ExcludeLinesTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/ExcludeLinesTest.java index 7e4de64568..7150e95c5a 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/ExcludeLinesTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/ExcludeLinesTest.java @@ -4,19 +4,18 @@ package net.sourceforge.pmd; +import static java.util.Collections.emptyList; +import static net.sourceforge.pmd.util.CollectionUtil.listOf; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import java.io.File; -import java.io.StringReader; - import org.junit.Before; import org.junit.Test; -import net.sourceforge.pmd.lang.LanguageRegistry; -import net.sourceforge.pmd.lang.java.JavaLanguageModule; +import net.sourceforge.pmd.processor.PmdRunnable; import net.sourceforge.pmd.testframework.RuleTst; import net.sourceforge.pmd.testframework.TestDescriptor; +import net.sourceforge.pmd.util.datasource.DataSource; public class ExcludeLinesTest extends RuleTst { private Rule rule; @@ -34,15 +33,19 @@ public class ExcludeLinesTest extends RuleTst { @Test public void testAlternateMarker() throws Exception { - PMD p = new PMD(); - p.getConfiguration().setSuppressMarker("FOOBAR"); - RuleContext ctx = new RuleContext(); - Report r = new Report(); - ctx.setReport(r); - ctx.setSourceCodeFile(new File("n/a")); - ctx.setLanguageVersion(LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getDefaultVersion()); + PMDConfiguration config = new PMDConfiguration(); + config.setSuppressMarker("FOOBAR"); + RuleSet rules = RulesetsFactoryUtils.defaultFactory().createSingleRuleRuleSet(rule); - p.getSourceCodeProcessor().processSourceCode(new StringReader(TEST3), new RuleSets(rules), ctx); + + Report r = new PmdRunnable( + DataSource.forString(TEST3, "test.java"), + emptyList(), + new RuleContext(), + listOf(rules), + config + ).call(); + assertTrue(r.getViolations().isEmpty()); assertEquals(r.getSuppressedViolations().size(), 1); } diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/XPathRuleTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/XPathRuleTest.java index ad15ca92f8..cbbae51162 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/XPathRuleTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/XPathRuleTest.java @@ -4,22 +4,22 @@ package net.sourceforge.pmd.lang.java.rule; +import static net.sourceforge.pmd.util.CollectionUtil.listOf; import static org.junit.Assert.assertEquals; -import java.io.File; -import java.io.StringReader; +import java.util.Collections; import java.util.HashMap; import java.util.List; import org.junit.Test; import net.sourceforge.pmd.PMD; +import net.sourceforge.pmd.PMDConfiguration; import net.sourceforge.pmd.PMDException; import net.sourceforge.pmd.Report; import net.sourceforge.pmd.Rule; import net.sourceforge.pmd.RuleContext; import net.sourceforge.pmd.RuleSet; -import net.sourceforge.pmd.RuleSets; import net.sourceforge.pmd.RuleViolation; import net.sourceforge.pmd.RulesetsFactoryUtils; import net.sourceforge.pmd.lang.LanguageRegistry; @@ -32,9 +32,11 @@ import net.sourceforge.pmd.lang.rule.XPathRule; import net.sourceforge.pmd.lang.rule.xpath.XPathVersion; import net.sourceforge.pmd.lang.rule.xpath.internal.DeprecatedAttrLogger; import net.sourceforge.pmd.lang.rule.xpath.internal.SaxonXPathRuleQuery; +import net.sourceforge.pmd.processor.PmdRunnable; import net.sourceforge.pmd.properties.PropertyDescriptor; import net.sourceforge.pmd.properties.PropertyFactory; import net.sourceforge.pmd.testframework.RuleTst; +import net.sourceforge.pmd.util.datasource.DataSource; /** * @author daniels @@ -170,14 +172,14 @@ public class XPathRuleTest extends RuleTst { } private static Report getReportForTestString(Rule r, String test) throws PMDException { - PMD p = new PMD(); - RuleContext ctx = new RuleContext(); - Report report = new Report(); - ctx.setReport(report); - ctx.setSourceCodeFile(new File("n/a")); RuleSet rules = RulesetsFactoryUtils.defaultFactory().createSingleRuleRuleSet(r); - p.getSourceCodeProcessor().processSourceCode(new StringReader(test), new RuleSets(rules), ctx); - return report; + return new PmdRunnable( + DataSource.forString(test, "test.java"), + Collections.emptyList(), + RuleContext.throwingExceptions(), + listOf(rules), + new PMDConfiguration() + ).call(); } diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/xpath/internal/XPathMetricFunctionTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/xpath/internal/XPathMetricFunctionTest.java index 9ac87e229b..e483fa31f2 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/xpath/internal/XPathMetricFunctionTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/xpath/internal/XPathMetricFunctionTest.java @@ -4,28 +4,31 @@ package net.sourceforge.pmd.lang.java.rule.xpath.internal; +import static net.sourceforge.pmd.util.CollectionUtil.listOf; import static org.junit.Assert.assertTrue; -import java.io.File; -import java.io.StringReader; +import java.util.Collections; import java.util.Iterator; +import org.hamcrest.CoreMatchers; +import org.hamcrest.Matchers; import org.junit.Test; import org.junit.rules.ExpectedException; -import net.sourceforge.pmd.PMD; +import net.sourceforge.pmd.PMDConfiguration; import net.sourceforge.pmd.PMDException; -import net.sourceforge.pmd.Report; import net.sourceforge.pmd.Rule; import net.sourceforge.pmd.RuleContext; import net.sourceforge.pmd.RuleSet; -import net.sourceforge.pmd.RuleSets; import net.sourceforge.pmd.RuleViolation; import net.sourceforge.pmd.RulesetsFactoryUtils; import net.sourceforge.pmd.lang.LanguageRegistry; +import net.sourceforge.pmd.lang.ast.FileAnalysisException; import net.sourceforge.pmd.lang.java.JavaLanguageModule; import net.sourceforge.pmd.lang.rule.XPathRule; import net.sourceforge.pmd.lang.rule.xpath.XPathVersion; +import net.sourceforge.pmd.processor.PmdRunnable; +import net.sourceforge.pmd.util.datasource.DataSource; /** * @author Clément Fournier @@ -47,16 +50,16 @@ public class XPathMetricFunctionTest { } - private Iterator getViolations(Rule rule, String code) throws PMDException { - PMD p = new PMD(); - RuleContext ctx = new RuleContext(); - Report report = new Report(); - ctx.setReport(report); - ctx.setSourceCodeFile(new File("n/a")); - ctx.setIgnoreExceptions(false); // for test, we want immediate exceptions thrown and not collect them + private Iterator getViolations(Rule rule, String code) { RuleSet rules = RulesetsFactoryUtils.defaultFactory().createSingleRuleRuleSet(rule); - p.getSourceCodeProcessor().processSourceCode(new StringReader(code), new RuleSets(rules), ctx); - return report.getViolations().iterator(); + + return new PmdRunnable( + DataSource.forString(code, "test.java"), + Collections.emptyList(), + RuleContext.throwingExceptions(), + listOf(rules), + new PMDConfiguration() + ).call().getViolations().iterator(); } @@ -132,15 +135,11 @@ public class XPathMetricFunctionTest { Rule rule = makeXpathRuleFromXPath(xpath); - expected.expect(expectedThrowable); - expected.expectMessage(expectedMessage); - - try { - getViolations(rule, code); - } catch (PMDException pmdE) { - throw (Exception) pmdE.getCause(); - } + expected.expect(FileAnalysisException.class); + expected.expectCause(Matchers.allOf(CoreMatchers.instanceOf(expectedThrowable), + Matchers.hasProperty("message", Matchers.equalTo(expectedMessage)))); + getViolations(rule, code); } diff --git a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/Ecmascript3Handler.java b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/Ecmascript3Handler.java index 9a6fd84912..bbec77ea90 100644 --- a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/Ecmascript3Handler.java +++ b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/Ecmascript3Handler.java @@ -20,7 +20,7 @@ public class Ecmascript3Handler extends AbstractPmdLanguageVersionHandler { @Override public Parser getParser(ParserOptions parserOptions) { - return new Ecmascript3Parser(parserOptions); + return new Ecmascript3Parser((EcmascriptParserOptions) parserOptions); } } diff --git a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/Ecmascript3Parser.java b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/Ecmascript3Parser.java index 2c672f94bc..51f712ba8d 100644 --- a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/Ecmascript3Parser.java +++ b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/Ecmascript3Parser.java @@ -4,28 +4,25 @@ package net.sourceforge.pmd.lang.ecmascript; -import java.io.Reader; - -import net.sourceforge.pmd.lang.AbstractParser; -import net.sourceforge.pmd.lang.ParserOptions; +import net.sourceforge.pmd.lang.Parser; import net.sourceforge.pmd.lang.ast.ParseException; import net.sourceforge.pmd.lang.ecmascript.ast.ASTAstRoot; +import net.sourceforge.pmd.lang.ecmascript.ast.EcmascriptParser; /** * Adapter for the EcmascriptParser. */ -public class Ecmascript3Parser extends AbstractParser { - private net.sourceforge.pmd.lang.ecmascript.ast.EcmascriptParser ecmascriptParser; +public class Ecmascript3Parser implements Parser { + private EcmascriptParser ecmascriptParser; - public Ecmascript3Parser(ParserOptions parserOptions) { - super(parserOptions); - ecmascriptParser = new net.sourceforge.pmd.lang.ecmascript.ast.EcmascriptParser( - (EcmascriptParserOptions) parserOptions); + public Ecmascript3Parser(EcmascriptParserOptions parserOptions) { + super(); + ecmascriptParser = new EcmascriptParser(parserOptions); } @Override - public ASTAstRoot parse(String fileName, Reader source) throws ParseException { - return ecmascriptParser.parse(source); + public ASTAstRoot parse(ParserTask task) throws ParseException { + return ecmascriptParser.parse(task); } } 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 27cafd1219..18aae28613 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 @@ -4,14 +4,11 @@ package net.sourceforge.pmd.lang.ecmascript.ast; -import java.io.IOException; -import java.io.Reader; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import org.apache.commons.io.IOUtils; import org.mozilla.javascript.CompilerEnvirons; import org.mozilla.javascript.Parser; import org.mozilla.javascript.ast.AstRoot; @@ -19,6 +16,7 @@ import org.mozilla.javascript.ast.Comment; import org.mozilla.javascript.ast.ErrorCollector; import org.mozilla.javascript.ast.ParseProblem; +import net.sourceforge.pmd.lang.Parser.ParserTask; import net.sourceforge.pmd.lang.ast.ParseException; import net.sourceforge.pmd.lang.ecmascript.EcmascriptParserOptions; @@ -58,30 +56,26 @@ public class EcmascriptParser { return astRoot; } - public ASTAstRoot parse(final Reader reader) { - try { - final List parseProblems = new ArrayList<>(); - final String sourceCode = IOUtils.toString(reader); - final AstRoot astRoot = parseEcmascript(sourceCode, parseProblems); - final EcmascriptTreeBuilder treeBuilder = new EcmascriptTreeBuilder(sourceCode, parseProblems); - ASTAstRoot tree = (ASTAstRoot) treeBuilder.build(astRoot); + public ASTAstRoot parse(final ParserTask task) { + final List parseProblems = new ArrayList<>(); + final String sourceCode = task.getSourceText(); + final AstRoot astRoot = parseEcmascript(sourceCode, parseProblems); + final EcmascriptTreeBuilder treeBuilder = new EcmascriptTreeBuilder(sourceCode, parseProblems); + ASTAstRoot tree = (ASTAstRoot) treeBuilder.build(astRoot); - suppressMap = new HashMap<>(); - if (astRoot.getComments() != null) { - for (Comment comment : astRoot.getComments()) { - int nopmd = comment.getValue().indexOf(suppressMarker); - if (nopmd > -1) { - String suppression = comment.getValue().substring(nopmd + suppressMarker.length()); - EcmascriptNode node = treeBuilder.build(comment); - suppressMap.put(node.getBeginLine(), suppression); - } + suppressMap = new HashMap<>(); + if (astRoot.getComments() != null) { + for (Comment comment : astRoot.getComments()) { + int nopmd = comment.getValue().indexOf(suppressMarker); + if (nopmd > -1) { + String suppression = comment.getValue().substring(nopmd + suppressMarker.length()); + EcmascriptNode node = treeBuilder.build(comment); + suppressMap.put(node.getBeginLine(), suppression); } } - tree.setNoPmdComments(suppressMap); - return tree; - } catch (IOException e) { - throw new ParseException(e); } + tree.setNoPmdComments(suppressMap); + return tree; } public Map getSuppressMap() { diff --git a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/JspHandler.java b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/JspHandler.java index ebfa9b7785..578c7e186a 100644 --- a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/JspHandler.java +++ b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/JspHandler.java @@ -18,7 +18,7 @@ public class JspHandler extends AbstractPmdLanguageVersionHandler { @Override public Parser getParser(ParserOptions parserOptions) { - return new JspParser(parserOptions); + return new JspParser(); } } diff --git a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/JspParser.java b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/JspParser.java index 33b7002294..e0380cf30e 100644 --- a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/JspParser.java +++ b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/JspParser.java @@ -6,7 +6,6 @@ package net.sourceforge.pmd.lang.jsp.ast; import org.checkerframework.checker.nullness.qual.Nullable; -import net.sourceforge.pmd.lang.ParserOptions; import net.sourceforge.pmd.lang.ast.CharStream; import net.sourceforge.pmd.lang.ast.ParseException; import net.sourceforge.pmd.lang.ast.impl.javacc.JavaccTokenDocument; @@ -17,10 +16,6 @@ import net.sourceforge.pmd.lang.ast.impl.javacc.JjtreeParserAdapter; */ public final class JspParser extends JjtreeParserAdapter { - public JspParser(ParserOptions parserOptions) { - super(parserOptions); - } - @Override protected JavaccTokenDocument newDocument(String fullText) { return new JavaccTokenDocument(fullText) { @@ -32,7 +27,7 @@ public final class JspParser extends JjtreeParserAdapter { } @Override - protected ASTCompilationUnit parseImpl(CharStream cs, ParserOptions options) throws ParseException { + protected ASTCompilationUnit parseImpl(CharStream cs, String suppressMarker) throws ParseException { return new JspParserImpl(cs).CompilationUnit(); } diff --git a/pmd-jsp/src/test/java/net/sourceforge/pmd/lang/jsp/ast/XPathJspRuleTest.java b/pmd-jsp/src/test/java/net/sourceforge/pmd/lang/jsp/ast/XPathJspRuleTest.java index 90b38f89a6..af52c00058 100644 --- a/pmd-jsp/src/test/java/net/sourceforge/pmd/lang/jsp/ast/XPathJspRuleTest.java +++ b/pmd-jsp/src/test/java/net/sourceforge/pmd/lang/jsp/ast/XPathJspRuleTest.java @@ -4,26 +4,28 @@ package net.sourceforge.pmd.lang.jsp.ast; +import static net.sourceforge.pmd.util.CollectionUtil.listOf; import static org.junit.Assert.assertEquals; -import java.io.StringReader; +import java.util.Collections; import org.junit.Test; -import net.sourceforge.pmd.PMD; +import net.sourceforge.pmd.PMDConfiguration; import net.sourceforge.pmd.PMDException; import net.sourceforge.pmd.Report; import net.sourceforge.pmd.Rule; import net.sourceforge.pmd.RuleContext; import net.sourceforge.pmd.RuleSet; -import net.sourceforge.pmd.RuleSets; import net.sourceforge.pmd.RuleViolation; import net.sourceforge.pmd.RulesetsFactoryUtils; import net.sourceforge.pmd.lang.LanguageRegistry; import net.sourceforge.pmd.lang.jsp.JspLanguageModule; import net.sourceforge.pmd.lang.rule.XPathRule; import net.sourceforge.pmd.lang.rule.xpath.XPathVersion; +import net.sourceforge.pmd.processor.PmdRunnable; import net.sourceforge.pmd.testframework.RuleTst; +import net.sourceforge.pmd.util.datasource.DataSource; public class XPathJspRuleTest extends RuleTst { @@ -36,17 +38,16 @@ public class XPathJspRuleTest extends RuleTst { Rule rule = new XPathRule(XPathVersion.XPATH_3_1, XPATH_EXPRESSION); rule.setMessage("Test"); rule.setLanguage(LanguageRegistry.getLanguage(JspLanguageModule.NAME)); + RuleSet rules = RulesetsFactoryUtils.defaultFactory().createSingleRuleRuleSet(rule); - RuleContext ctx = new RuleContext(); - Report report = new Report(); - ctx.setReport(report); - ctx.setSourceCodeFilename("n/a"); - ctx.setLanguageVersion(LanguageRegistry.getLanguage(JspLanguageModule.NAME).getDefaultVersion()); - - PMD p = new PMD(); - - p.getSourceCodeProcessor().processSourceCode(new StringReader(MATCH), new RuleSets(rules), ctx); + Report report = new PmdRunnable( + DataSource.forString(MATCH, "test.jsp"), + Collections.emptyList(), + RuleContext.throwingExceptions(), + listOf(rules), + new PMDConfiguration() + ).call(); assertEquals("One violation expected!", 1, report.getViolations().size()); 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 41ef8181f4..3828b481c1 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 @@ -3,14 +3,8 @@ */ package net.sourceforge.pmd.lang.ast.test -import net.sourceforge.pmd.lang.LanguageRegistry -import net.sourceforge.pmd.lang.LanguageVersion -import net.sourceforge.pmd.lang.LanguageVersionHandler -import net.sourceforge.pmd.lang.ParserOptions -import net.sourceforge.pmd.lang.ast.AstAnalysisContext; -import net.sourceforge.pmd.lang.ast.AstProcessingStage -import net.sourceforge.pmd.lang.ast.Node -import net.sourceforge.pmd.lang.ast.RootNode +import net.sourceforge.pmd.lang.* +import net.sourceforge.pmd.lang.ast.* import org.apache.commons.io.IOUtils import java.io.InputStream import java.io.StringReader @@ -116,7 +110,8 @@ abstract class BaseParsingHelper, T : RootNode val handler = lversion.languageVersionHandler val options = params.parserOptions ?: handler.defaultParserOptions val parser = handler.getParser(options) - val rootNode = rootClass.cast(parser.parse(null, StringReader(sourceCode))) + val task = Parser.ParserTask(lversion, "test-file", sourceCode, SemanticErrorReporter.noop()) + val rootNode = rootClass.cast(parser.parse(task)) if (params.doProcess) { postProcessing(handler, lversion, rootNode) } diff --git a/pmd-modelica/src/main/java/net/sourceforge/pmd/lang/modelica/ModelicaHandler.java b/pmd-modelica/src/main/java/net/sourceforge/pmd/lang/modelica/ModelicaHandler.java index 156d57f120..cac6cb273e 100644 --- a/pmd-modelica/src/main/java/net/sourceforge/pmd/lang/modelica/ModelicaHandler.java +++ b/pmd-modelica/src/main/java/net/sourceforge/pmd/lang/modelica/ModelicaHandler.java @@ -20,7 +20,7 @@ public class ModelicaHandler extends AbstractPmdLanguageVersionHandler { @Override public Parser getParser(ParserOptions parserOptions) { - return new ModelicaParser(parserOptions); + return new ModelicaParser(); } } diff --git a/pmd-modelica/src/main/java/net/sourceforge/pmd/lang/modelica/ast/ModelicaParser.java b/pmd-modelica/src/main/java/net/sourceforge/pmd/lang/modelica/ast/ModelicaParser.java index 5c1bd012d1..b3d2a88abe 100644 --- a/pmd-modelica/src/main/java/net/sourceforge/pmd/lang/modelica/ast/ModelicaParser.java +++ b/pmd-modelica/src/main/java/net/sourceforge/pmd/lang/modelica/ast/ModelicaParser.java @@ -4,7 +4,6 @@ package net.sourceforge.pmd.lang.modelica.ast; -import net.sourceforge.pmd.lang.ParserOptions; import net.sourceforge.pmd.lang.ast.CharStream; import net.sourceforge.pmd.lang.ast.ParseException; import net.sourceforge.pmd.lang.ast.impl.javacc.JavaccTokenDocument; @@ -13,17 +12,13 @@ import net.sourceforge.pmd.lang.ast.impl.javacc.JjtreeParserAdapter; public class ModelicaParser extends JjtreeParserAdapter { - public ModelicaParser(final ParserOptions parserOptions) { - super(parserOptions); - } - @Override protected JavaccTokenDocument newDocument(String fullText) { return new ModelicaTokenDocument(fullText); } @Override - protected ASTStoredDefinition parseImpl(CharStream cs, ParserOptions options) throws ParseException { + protected ASTStoredDefinition parseImpl(CharStream cs, String suppressMarker) throws ParseException { return new ModelicaParserImpl(cs).StoredDefinition(); } diff --git a/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/PLSQLHandler.java b/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/PLSQLHandler.java index 4ac9bda861..af4aa21a8c 100644 --- a/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/PLSQLHandler.java +++ b/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/PLSQLHandler.java @@ -24,7 +24,7 @@ public class PLSQLHandler extends AbstractPmdLanguageVersionHandler { @Override public Parser getParser(ParserOptions parserOptions) { - return new PLSQLParser(parserOptions); + return new PLSQLParser(); } } diff --git a/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/PLSQLParser.java b/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/PLSQLParser.java index 2661c5063e..ec4550a91f 100644 --- a/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/PLSQLParser.java +++ b/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/PLSQLParser.java @@ -4,23 +4,15 @@ package net.sourceforge.pmd.lang.plsql.ast; -import java.io.Reader; - import org.checkerframework.checker.nullness.qual.Nullable; -import net.sourceforge.pmd.lang.ParserOptions; import net.sourceforge.pmd.lang.ast.CharStream; 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.util.IOUtil; public class PLSQLParser extends JjtreeParserAdapter { - public PLSQLParser(ParserOptions parserOptions) { - super(parserOptions); - } - @Override protected JavaccTokenDocument newDocument(String fullText) { return new JavaccTokenDocument(fullText) { @@ -32,12 +24,7 @@ public class PLSQLParser extends JjtreeParserAdapter { } @Override - public ASTInput parse(String fileName, Reader source) throws ParseException { - return super.parse(fileName, IOUtil.skipBOM(source)); - } - - @Override - protected ASTInput parseImpl(CharStream cs, ParserOptions options) throws ParseException { + protected ASTInput parseImpl(CharStream cs, String suppressMarker) throws ParseException { return new PLSQLParserImpl(cs).Input(); } diff --git a/pmd-scala-modules/pmd-scala-common/src/main/java/net/sourceforge/pmd/lang/scala/ast/ScalaParser.java b/pmd-scala-modules/pmd-scala-common/src/main/java/net/sourceforge/pmd/lang/scala/ast/ScalaParser.java index 7756e95c66..fd4bb04d77 100644 --- a/pmd-scala-modules/pmd-scala-common/src/main/java/net/sourceforge/pmd/lang/scala/ast/ScalaParser.java +++ b/pmd-scala-modules/pmd-scala-common/src/main/java/net/sourceforge/pmd/lang/scala/ast/ScalaParser.java @@ -4,12 +4,7 @@ package net.sourceforge.pmd.lang.scala.ast; -import java.io.IOException; -import java.io.Reader; - -import org.apache.commons.io.IOUtils; - -import net.sourceforge.pmd.lang.AbstractParser; +import net.sourceforge.pmd.lang.Parser; import net.sourceforge.pmd.lang.ParserOptions; import net.sourceforge.pmd.lang.ast.ParseException; @@ -23,7 +18,7 @@ import scala.meta.internal.parsers.ScalametaParser; * Scalameta. This parser then wraps all of ScalaMeta's Nodes in Java versions * for compatibility. */ -public final class ScalaParser extends AbstractParser { +public final class ScalaParser implements Parser { private final Dialect dialect; /** @@ -35,19 +30,13 @@ public final class ScalaParser extends AbstractParser { * any additional options for this parser */ public ScalaParser(Dialect scalaDialect, ParserOptions parserOptions) { - super(parserOptions); + super(); this.dialect = scalaDialect; } @Override - public ASTSource parse(String fileName, Reader source) throws ParseException { - Input.VirtualFile virtualFile; - try { - String sourceString = IOUtils.toString(source); - virtualFile = new Input.VirtualFile(fileName, sourceString); - } catch (IOException e) { - throw new ParseException(e); - } + public ASTSource parse(ParserTask task) throws ParseException { + Input.VirtualFile virtualFile = new Input.VirtualFile(task.getFileDisplayName(), task.getSourceText()); Source src = new ScalametaParser(virtualFile, dialect).parseSource(); return (ASTSource) new ScalaTreeBuilder().build(src); } diff --git a/pmd-scala-modules/pmd-scala-common/src/test/java/net/sourceforge/pmd/lang/scala/ast/ScalaParsingHelper.java b/pmd-scala-modules/pmd-scala-common/src/test/java/net/sourceforge/pmd/lang/scala/ast/ScalaParsingHelper.java index 1f37f484c7..697bdc98b9 100644 --- a/pmd-scala-modules/pmd-scala-common/src/test/java/net/sourceforge/pmd/lang/scala/ast/ScalaParsingHelper.java +++ b/pmd-scala-modules/pmd-scala-common/src/test/java/net/sourceforge/pmd/lang/scala/ast/ScalaParsingHelper.java @@ -4,19 +4,20 @@ package net.sourceforge.pmd.lang.scala.ast; -import java.io.File; -import java.io.StringReader; +import static net.sourceforge.pmd.util.CollectionUtil.listOf; -import net.sourceforge.pmd.PMD; -import net.sourceforge.pmd.PMDException; +import java.util.Collections; + +import net.sourceforge.pmd.PMDConfiguration; import net.sourceforge.pmd.Report; import net.sourceforge.pmd.Rule; import net.sourceforge.pmd.RuleContext; import net.sourceforge.pmd.RuleSet; -import net.sourceforge.pmd.RuleSetFactory; -import net.sourceforge.pmd.RuleSets; +import net.sourceforge.pmd.RulesetsFactoryUtils; import net.sourceforge.pmd.lang.ast.test.BaseParsingHelper; import net.sourceforge.pmd.lang.scala.ScalaLanguageModule; +import net.sourceforge.pmd.processor.PmdRunnable; +import net.sourceforge.pmd.util.datasource.DataSource; public final class ScalaParsingHelper extends BaseParsingHelper { @@ -33,18 +34,14 @@ public final class ScalaParsingHelper extends BaseParsingHelper { + DummyRootNode node = new DummyRootNode(); + node.setCoords(1, 1, 1, 2); + node.setImage("Foo"); + return node; }; } } 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 a4a6fa85b6..ee51ae9132 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 @@ -4,13 +4,12 @@ package net.sourceforge.pmd.testframework; +import static net.sourceforge.pmd.util.CollectionUtil.listOf; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; -import java.io.File; import java.io.IOException; import java.io.InputStream; -import java.io.StringReader; import java.io.StringWriter; import java.util.ArrayList; import java.util.Collections; @@ -34,21 +33,22 @@ import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; -import net.sourceforge.pmd.PMD; +import net.sourceforge.pmd.PMDConfiguration; import net.sourceforge.pmd.PMDException; import net.sourceforge.pmd.Report; import net.sourceforge.pmd.Rule; import net.sourceforge.pmd.RuleContext; import net.sourceforge.pmd.RuleSet; import net.sourceforge.pmd.RuleSetNotFoundException; -import net.sourceforge.pmd.RuleSets; import net.sourceforge.pmd.RuleViolation; import net.sourceforge.pmd.RulesetsFactoryUtils; import net.sourceforge.pmd.lang.Language; import net.sourceforge.pmd.lang.LanguageRegistry; import net.sourceforge.pmd.lang.LanguageVersion; +import net.sourceforge.pmd.processor.PmdRunnable; import net.sourceforge.pmd.properties.PropertyDescriptor; import net.sourceforge.pmd.renderers.TextRenderer; +import net.sourceforge.pmd.util.datasource.DataSource; /** * Advanced methods for test cases @@ -265,18 +265,18 @@ public abstract class RuleTst { public void runTestFromString(String code, Rule rule, Report report, LanguageVersion languageVersion, boolean isUseAuxClasspath) { try { - PMD p = new PMD(); - p.getConfiguration().setDefaultLanguageVersion(languageVersion); - p.getConfiguration().setIgnoreIncrementalAnalysis(true); + PMDConfiguration config = new PMDConfiguration(); + config.setIgnoreIncrementalAnalysis(true); + if (isUseAuxClasspath) { // configure the "auxclasspath" option for unit testing - p.getConfiguration().prependClasspath("."); + config.prependClasspath("."); } else { // simple class loader, that doesn't delegate to parent. // this allows us in the tests to simulate PMD run without // auxclasspath, not even the classes from the test dependencies // will be found. - p.getConfiguration().setClassLoader(new ClassLoader() { + config.setClassLoader(new ClassLoader() { @Override protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { if (name.startsWith("java.") || name.startsWith("javax.")) { @@ -286,13 +286,20 @@ public abstract class RuleTst { } }); } - RuleContext ctx = new RuleContext(); + + RuleContext ctx = RuleContext.throwingExceptions(); ctx.setReport(report); - ctx.setSourceCodeFile(new File("n/a")); ctx.setLanguageVersion(languageVersion); - ctx.setIgnoreExceptions(false); RuleSet rules = RulesetsFactoryUtils.defaultFactory().createSingleRuleRuleSet(rule); - p.getSourceCodeProcessor().processSourceCode(new StringReader(code), new RuleSets(rules), ctx); + + report.merge(new PmdRunnable( + DataSource.forString(code, "test." + languageVersion.getLanguage().getExtensions().get(0)), + Collections.emptyList(), + ctx, + listOf(rules), + config + ).call()); + } catch (Exception e) { throw new RuntimeException(e); } 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 734c742be1..fa953b9fef 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 @@ -13,7 +13,7 @@ public class VfHandler extends AbstractPmdLanguageVersionHandler { @Override public Parser getParser(ParserOptions parserOptions) { - return new VfParser(parserOptions); + return new VfParser(); } } 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 1a288cc52b..bc33ababc8 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 @@ -6,7 +6,6 @@ package net.sourceforge.pmd.lang.vf.ast; import org.checkerframework.checker.nullness.qual.Nullable; -import net.sourceforge.pmd.lang.ParserOptions; import net.sourceforge.pmd.lang.ast.CharStream; import net.sourceforge.pmd.lang.ast.ParseException; import net.sourceforge.pmd.lang.ast.impl.javacc.JavaccTokenDocument; @@ -17,10 +16,6 @@ import net.sourceforge.pmd.lang.ast.impl.javacc.JjtreeParserAdapter; */ public final class VfParser extends JjtreeParserAdapter { - public VfParser(ParserOptions parserOptions) { - super(parserOptions); - } - @Override protected JavaccTokenDocument newDocument(String fullText) { return new JavaccTokenDocument(fullText) { @@ -32,7 +27,7 @@ public final class VfParser extends JjtreeParserAdapter { } @Override - protected ASTCompilationUnit parseImpl(CharStream cs, ParserOptions options) throws ParseException { + protected ASTCompilationUnit parseImpl(CharStream cs, String suppressMarker) throws ParseException { return new VfParserImpl(cs).CompilationUnit(); } diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/VmHandler.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/VmHandler.java index b6221bc874..8632d9d0bf 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/VmHandler.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/VmHandler.java @@ -18,7 +18,7 @@ public class VmHandler extends AbstractPmdLanguageVersionHandler { @Override public Parser getParser(final ParserOptions parserOptions) { - return new VmParser(parserOptions); + return new VmParser(); } } diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/VmParser.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/VmParser.java index 09f53ca99e..d89e848f35 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/VmParser.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/VmParser.java @@ -6,7 +6,6 @@ package net.sourceforge.pmd.lang.vm.ast; import org.checkerframework.checker.nullness.qual.Nullable; -import net.sourceforge.pmd.lang.ParserOptions; import net.sourceforge.pmd.lang.ast.CharStream; import net.sourceforge.pmd.lang.ast.ParseException; import net.sourceforge.pmd.lang.ast.impl.javacc.JavaccToken; @@ -18,17 +17,13 @@ import net.sourceforge.pmd.lang.ast.impl.javacc.JjtreeParserAdapter; */ public class VmParser extends JjtreeParserAdapter { - public VmParser(final ParserOptions parserOptions) { - super(parserOptions); - } - @Override protected JavaccTokenDocument newDocument(String fullText) { return new VmTokenDocument(fullText); } @Override - protected ASTTemplate parseImpl(CharStream cs, ParserOptions options) throws ParseException { + protected ASTTemplate parseImpl(CharStream cs, String suppressMarker) throws ParseException { return new VmParserImpl(cs).Template(); } diff --git a/pmd-xml/src/main/java/net/sourceforge/pmd/lang/xml/XmlHandler.java b/pmd-xml/src/main/java/net/sourceforge/pmd/lang/xml/XmlHandler.java index 97d79e8b5d..2613c0a183 100644 --- a/pmd-xml/src/main/java/net/sourceforge/pmd/lang/xml/XmlHandler.java +++ b/pmd-xml/src/main/java/net/sourceforge/pmd/lang/xml/XmlHandler.java @@ -20,7 +20,7 @@ public class XmlHandler extends AbstractPmdLanguageVersionHandler { @Override public Parser getParser(ParserOptions parserOptions) { - return new XmlParser(parserOptions); + return new XmlParser((XmlParserOptions) parserOptions); } } diff --git a/pmd-xml/src/main/java/net/sourceforge/pmd/lang/xml/XmlParser.java b/pmd-xml/src/main/java/net/sourceforge/pmd/lang/xml/XmlParser.java index 7b3a9a2935..3c23d5c421 100644 --- a/pmd-xml/src/main/java/net/sourceforge/pmd/lang/xml/XmlParser.java +++ b/pmd-xml/src/main/java/net/sourceforge/pmd/lang/xml/XmlParser.java @@ -4,10 +4,7 @@ package net.sourceforge.pmd.lang.xml; -import java.io.Reader; - -import net.sourceforge.pmd.lang.AbstractParser; -import net.sourceforge.pmd.lang.ParserOptions; +import net.sourceforge.pmd.lang.Parser; import net.sourceforge.pmd.lang.ast.ParseException; import net.sourceforge.pmd.lang.xml.ast.internal.XmlParserImpl; import net.sourceforge.pmd.lang.xml.ast.internal.XmlParserImpl.RootXmlNode; @@ -15,15 +12,16 @@ import net.sourceforge.pmd.lang.xml.ast.internal.XmlParserImpl.RootXmlNode; /** * Adapter for the XmlParser. */ -public class XmlParser extends AbstractParser { +public class XmlParser implements Parser { + private final XmlParserOptions parserOptions; - public XmlParser(ParserOptions parserOptions) { - super(parserOptions); + public XmlParser(XmlParserOptions parserOptions) { + this.parserOptions = parserOptions; } @Override - public RootXmlNode parse(String fileName, Reader source) throws ParseException { - return new XmlParserImpl((XmlParserOptions) parserOptions).parse(source); + public RootXmlNode parse(ParserTask task) throws ParseException { + return new XmlParserImpl(parserOptions).parse(task); } } diff --git a/pmd-xml/src/main/java/net/sourceforge/pmd/lang/xml/ast/internal/XmlParserImpl.java b/pmd-xml/src/main/java/net/sourceforge/pmd/lang/xml/ast/internal/XmlParserImpl.java index ddc433af6f..f61ada28a8 100644 --- a/pmd-xml/src/main/java/net/sourceforge/pmd/lang/xml/ast/internal/XmlParserImpl.java +++ b/pmd-xml/src/main/java/net/sourceforge/pmd/lang/xml/ast/internal/XmlParserImpl.java @@ -5,7 +5,6 @@ package net.sourceforge.pmd.lang.xml.ast.internal; import java.io.IOException; -import java.io.Reader; import java.io.StringReader; import java.util.HashMap; import java.util.Map; @@ -13,12 +12,12 @@ import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; -import org.apache.commons.io.IOUtils; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.xml.sax.InputSource; import org.xml.sax.SAXException; +import net.sourceforge.pmd.lang.Parser.ParserTask; import net.sourceforge.pmd.lang.ast.ParseException; import net.sourceforge.pmd.lang.ast.RootNode; import net.sourceforge.pmd.lang.xml.XmlParserOptions; @@ -59,13 +58,8 @@ public class XmlParserImpl { } - public RootXmlNode parse(Reader reader) { - String xmlData; - try { - xmlData = IOUtils.toString(reader); - } catch (IOException e) { - throw new ParseException(e); - } + public RootXmlNode parse(ParserTask task) { + String xmlData = task.getSourceText(); Document document = parseDocument(xmlData); RootXmlNode root = new RootXmlNode(this, document); DOMLineNumbers lineNumbers = new DOMLineNumbers(root, xmlData);