Merge branch '7.0.x' into java-grammar
This commit is contained in:
@ -31,7 +31,12 @@ This is a {{ site.pmd.release_type }} release.
|
||||
* {% jdoc java::lang.java.JavaLanguageHandler %}
|
||||
* {% jdoc java::lang.java.JavaLanguageParser %}
|
||||
* {% jdoc java::lang.java.JavaDataFlowHandler %}
|
||||
|
||||
* Implementations of {% jdoc core::lang.rule.RuleViolationFactory %} in each
|
||||
language module, eg {% jdoc java::lang.java.rule.JavaRuleViolationFactory %}.
|
||||
See javadoc of {% jdoc core::lang.rule.RuleViolationFactory %}.
|
||||
* Implementations of {% jdoc core::RuleViolation %} in each language module,
|
||||
eg {% jdoc java::lang.java.rule.JavaRuleViolation %}. See javadoc of
|
||||
{% jdoc core::RuleViolation %}.
|
||||
|
||||
##### For removal
|
||||
|
||||
|
@ -11,7 +11,6 @@ import net.sourceforge.pmd.lang.AbstractPmdLanguageVersionHandler;
|
||||
import net.sourceforge.pmd.lang.Parser;
|
||||
import net.sourceforge.pmd.lang.ParserOptions;
|
||||
import net.sourceforge.pmd.lang.VisitorStarter;
|
||||
import net.sourceforge.pmd.lang.XPathHandler;
|
||||
import net.sourceforge.pmd.lang.apex.ast.ASTMethod;
|
||||
import net.sourceforge.pmd.lang.apex.ast.ASTUserClassOrInterface;
|
||||
import net.sourceforge.pmd.lang.apex.ast.ApexNode;
|
||||
@ -19,8 +18,7 @@ import net.sourceforge.pmd.lang.apex.metrics.ApexMetricsComputer;
|
||||
import net.sourceforge.pmd.lang.apex.metrics.api.ApexClassMetricKey;
|
||||
import net.sourceforge.pmd.lang.apex.metrics.api.ApexOperationMetricKey;
|
||||
import net.sourceforge.pmd.lang.apex.multifile.ApexMultifileVisitorFacade;
|
||||
import net.sourceforge.pmd.lang.apex.rule.ApexRuleViolationFactory;
|
||||
import net.sourceforge.pmd.lang.ast.xpath.DefaultASTXPathHandler;
|
||||
import net.sourceforge.pmd.lang.apex.rule.internal.ApexRuleViolationFactory;
|
||||
import net.sourceforge.pmd.lang.metrics.LanguageMetricsProvider;
|
||||
import net.sourceforge.pmd.lang.metrics.internal.AbstractLanguageMetricsProvider;
|
||||
import net.sourceforge.pmd.lang.rule.RuleViolationFactory;
|
||||
@ -35,12 +33,6 @@ public class ApexHandler extends AbstractPmdLanguageVersionHandler {
|
||||
return rootNode -> new ApexMultifileVisitorFacade().initializeWith((ApexNode<?>) rootNode);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public XPathHandler getXPathHandler() {
|
||||
return new DefaultASTXPathHandler();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RuleViolationFactory getRuleViolationFactory() {
|
||||
return ApexRuleViolationFactory.INSTANCE;
|
||||
|
@ -5,7 +5,6 @@
|
||||
package net.sourceforge.pmd.lang.apex;
|
||||
|
||||
import java.io.Reader;
|
||||
import java.util.Map;
|
||||
|
||||
import net.sourceforge.pmd.lang.AbstractParser;
|
||||
import net.sourceforge.pmd.lang.ParserOptions;
|
||||
@ -34,8 +33,4 @@ public class ApexParser extends AbstractParser {
|
||||
return apexParser.parse(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Integer, String> getSuppressMap() {
|
||||
return apexParser.getSuppressMap();
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,9 @@
|
||||
|
||||
package net.sourceforge.pmd.lang.apex.ast;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import net.sourceforge.pmd.lang.ast.RootNode;
|
||||
import net.sourceforge.pmd.lang.ast.SourceCodePositioner;
|
||||
|
||||
@ -11,6 +14,9 @@ import apex.jorje.semantic.ast.AstNode;
|
||||
import apex.jorje.services.Version;
|
||||
|
||||
public abstract class ApexRootNode<T extends AstNode> extends AbstractApexNode<T> implements RootNode {
|
||||
|
||||
private Map<Integer, String> noPmdComments = Collections.emptyMap();
|
||||
|
||||
public ApexRootNode(T node) {
|
||||
super(node);
|
||||
}
|
||||
@ -32,4 +38,14 @@ public abstract class ApexRootNode<T extends AstNode> extends AbstractApexNode<T
|
||||
public double getApexVersion() {
|
||||
return getNode().getDefiningType().getCodeUnitDetails().getVersion().getExternal();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Map<Integer, String> getNoPmdComments() {
|
||||
return noPmdComments;
|
||||
}
|
||||
|
||||
void setNoPmdComments(Map<Integer, String> noPmdComments) {
|
||||
this.noPmdComments = noPmdComments;
|
||||
}
|
||||
}
|
||||
|
@ -1,69 +0,0 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.apex.rule;
|
||||
|
||||
import net.sourceforge.pmd.Rule;
|
||||
import net.sourceforge.pmd.RuleContext;
|
||||
import net.sourceforge.pmd.lang.apex.ast.CanSuppressWarnings;
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.rule.ParametricRuleViolation;
|
||||
|
||||
/**
|
||||
* This is an Apex RuleViolation. It knows how to try to extract the following
|
||||
* extra information from the violation node:
|
||||
* <ul>
|
||||
* <li>Package name</li>
|
||||
* <li>Class name</li>
|
||||
* <li>Method name</li>
|
||||
* <li>Variable name</li>
|
||||
* <li>Suppression indicator</li>
|
||||
* </ul>
|
||||
* @param <T>
|
||||
*/
|
||||
@SuppressWarnings("PMD.UseUtilityClass") // we inherit non-static methods...
|
||||
public class ApexRuleViolation<T> extends ParametricRuleViolation<Node> {
|
||||
|
||||
public ApexRuleViolation(Rule rule, RuleContext ctx, Node node, String message, int beginLine, int endLine) {
|
||||
this(rule, ctx, node, message);
|
||||
|
||||
setLines(beginLine, endLine);
|
||||
}
|
||||
|
||||
public ApexRuleViolation(Rule rule, RuleContext ctx, Node node, String message) {
|
||||
super(rule, ctx, node, message);
|
||||
|
||||
if (node != null) {
|
||||
if (!suppressed) {
|
||||
suppressed = isSupressed(node, getRule());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for suppression on this node, on parents, and on contained types
|
||||
* for ASTCompilationUnit
|
||||
*
|
||||
* @deprecated Is internal API, not useful, there's a typo. See <a href="https://github.com/pmd/pmd/pull/1927">#1927</a>
|
||||
*/
|
||||
@Deprecated
|
||||
public static boolean isSupressed(Node node, Rule rule) {
|
||||
boolean result = suppresses(node, rule);
|
||||
|
||||
if (!result) {
|
||||
Node parent = node.jjtGetParent();
|
||||
while (!result && parent != null) {
|
||||
result = suppresses(parent, rule);
|
||||
parent = parent.jjtGetParent();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static boolean suppresses(final Node node, Rule rule) {
|
||||
return node instanceof CanSuppressWarnings
|
||||
&& ((CanSuppressWarnings) node).hasSuppressWarningsAnnotationFor(rule);
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.apex.rule;
|
||||
|
||||
import net.sourceforge.pmd.Rule;
|
||||
import net.sourceforge.pmd.RuleContext;
|
||||
import net.sourceforge.pmd.RuleViolation;
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.rule.AbstractRuleViolationFactory;
|
||||
|
||||
public final class ApexRuleViolationFactory extends AbstractRuleViolationFactory {
|
||||
|
||||
public static final ApexRuleViolationFactory INSTANCE = new ApexRuleViolationFactory();
|
||||
|
||||
private ApexRuleViolationFactory() {
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
protected RuleViolation createRuleViolation(Rule rule, RuleContext ruleContext, Node node, String message) {
|
||||
return new ApexRuleViolation<>(rule, ruleContext, node, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
protected RuleViolation createRuleViolation(Rule rule, RuleContext ruleContext, Node node, String message,
|
||||
int beginLine, int endLine) {
|
||||
return new ApexRuleViolation(rule, ruleContext, node, message, beginLine, endLine);
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.apex.rule.internal;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import net.sourceforge.pmd.Report;
|
||||
import net.sourceforge.pmd.Report.SuppressedViolation;
|
||||
import net.sourceforge.pmd.Rule;
|
||||
import net.sourceforge.pmd.RuleViolation;
|
||||
import net.sourceforge.pmd.ViolationSuppressor;
|
||||
import net.sourceforge.pmd.lang.apex.ast.CanSuppressWarnings;
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.rule.impl.DefaultRuleViolationFactory;
|
||||
|
||||
public final class ApexRuleViolationFactory extends DefaultRuleViolationFactory {
|
||||
|
||||
public static final ApexRuleViolationFactory INSTANCE = new ApexRuleViolationFactory();
|
||||
private static final ViolationSuppressor APEX_ANNOT_SUPPRESSOR = new ViolationSuppressor() {
|
||||
@Override
|
||||
public String getId() {
|
||||
return "@SuppressWarnings";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Report.SuppressedViolation suppressOrNull(RuleViolation rv, @NonNull Node node) {
|
||||
if (isSuppressed(node, rv.getRule())) {
|
||||
return new SuppressedViolation(rv, this, null);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
private ApexRuleViolationFactory() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<ViolationSuppressor> getSuppressors() {
|
||||
return Collections.singletonList(APEX_ANNOT_SUPPRESSOR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for suppression on this node, on parents, and on contained types
|
||||
* for ASTCompilationUnit
|
||||
*
|
||||
* @param node
|
||||
*/
|
||||
private static boolean isSuppressed(Node node, Rule rule) {
|
||||
boolean result = suppresses(node, rule);
|
||||
|
||||
if (!result) {
|
||||
Node parent = node.jjtGetParent();
|
||||
while (!result && parent != null) {
|
||||
result = suppresses(parent, rule);
|
||||
parent = parent.jjtGetParent();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static boolean suppresses(final Node node, Rule rule) {
|
||||
return node instanceof CanSuppressWarnings
|
||||
&& ((CanSuppressWarnings) node).hasSuppressWarningsAnnotationFor(rule);
|
||||
}
|
||||
}
|
@ -42,7 +42,6 @@ public class Report implements Iterable<RuleViolation> {
|
||||
private final List<ThreadSafeReportListener> listeners = new ArrayList<>();
|
||||
private List<ProcessingError> errors;
|
||||
private List<ConfigurationError> configErrors;
|
||||
private Map<Integer, String> linesToSuppress = new HashMap<>();
|
||||
private long start;
|
||||
private long end;
|
||||
private List<SuppressedViolation> suppressedRuleViolations = new ArrayList<>();
|
||||
@ -177,72 +176,6 @@ public class Report implements Iterable<RuleViolation> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a violation, that has been suppressed.
|
||||
*/
|
||||
public static class SuppressedViolation {
|
||||
private final RuleViolation rv;
|
||||
private final boolean isNOPMD;
|
||||
private final String userMessage;
|
||||
|
||||
/**
|
||||
* Creates a suppressed violation.
|
||||
*
|
||||
* @param rv
|
||||
* the actual violation, that has been suppressed
|
||||
* @param isNOPMD
|
||||
* the suppression mode: <code>true</code> if it is
|
||||
* suppressed via a NOPMD comment, <code>false</code> if
|
||||
* suppressed via annotations.
|
||||
* @param userMessage
|
||||
* contains the suppressed code line or <code>null</code>
|
||||
*/
|
||||
public SuppressedViolation(RuleViolation rv, boolean isNOPMD, String userMessage) {
|
||||
this.isNOPMD = isNOPMD;
|
||||
this.rv = rv;
|
||||
this.userMessage = userMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if the violation has been suppressed via a
|
||||
* NOPMD comment.
|
||||
*
|
||||
* @return <code>true</code> if the violation has been suppressed via a
|
||||
* NOPMD comment.
|
||||
*/
|
||||
public boolean suppressedByNOPMD() {
|
||||
return this.isNOPMD;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if the violation has been suppressed via a
|
||||
* annotation.
|
||||
*
|
||||
* @return <code>true</code> if the violation has been suppressed via a
|
||||
* annotation.
|
||||
*/
|
||||
public boolean suppressedByAnnotation() {
|
||||
return !this.isNOPMD;
|
||||
}
|
||||
|
||||
public RuleViolation getRuleViolation() {
|
||||
return this.rv;
|
||||
}
|
||||
|
||||
public String getUserMessage() {
|
||||
return userMessage;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the lines, that are suppressed via a NOPMD comment.
|
||||
*
|
||||
* @param lines
|
||||
* the suppressed lines
|
||||
*/
|
||||
public void suppress(Map<Integer, String> lines) {
|
||||
linesToSuppress = lines;
|
||||
}
|
||||
|
||||
private static String keyFor(RuleViolation rv) {
|
||||
|
||||
@ -301,6 +234,46 @@ public class Report implements Iterable<RuleViolation> {
|
||||
return suppressedRuleViolations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a violation, that has been suppressed.
|
||||
* TODO this should implement RuleViolation
|
||||
*/
|
||||
public static class SuppressedViolation {
|
||||
private final RuleViolation rv;
|
||||
private final String userMessage;
|
||||
private final ViolationSuppressor suppressor;
|
||||
|
||||
/**
|
||||
* Creates a suppressed violation.
|
||||
*
|
||||
* @param rv The violation, that has been suppressed
|
||||
* @param suppressor The suppressor which suppressed the violation
|
||||
* @param userMessage Any relevant info given by the suppressor
|
||||
*/
|
||||
public SuppressedViolation(RuleViolation rv, ViolationSuppressor suppressor, String userMessage) {
|
||||
this.suppressor = suppressor;
|
||||
this.rv = rv;
|
||||
this.userMessage = userMessage;
|
||||
}
|
||||
|
||||
public ViolationSuppressor getSuppressor() {
|
||||
return suppressor;
|
||||
}
|
||||
|
||||
public RuleViolation getRuleViolation() {
|
||||
return this.rv;
|
||||
}
|
||||
|
||||
public String getUserMessage() {
|
||||
return userMessage;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void addSuppressedViolation(SuppressedViolation sv) {
|
||||
suppressedRuleViolations.add(sv);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new rule violation to the report and notify the listeners.
|
||||
*
|
||||
@ -308,19 +281,6 @@ public class Report implements Iterable<RuleViolation> {
|
||||
* the violation to add
|
||||
*/
|
||||
public void addRuleViolation(RuleViolation violation) {
|
||||
|
||||
// NOPMD suppress
|
||||
int line = violation.getBeginLine();
|
||||
if (linesToSuppress.containsKey(line)) {
|
||||
suppressedRuleViolations.add(new SuppressedViolation(violation, true, linesToSuppress.get(line)));
|
||||
return;
|
||||
}
|
||||
|
||||
if (violation.isSuppressed()) {
|
||||
suppressedRuleViolations.add(new SuppressedViolation(violation, false, null));
|
||||
return;
|
||||
}
|
||||
|
||||
int index = Collections.binarySearch(violations, violation, RuleViolationComparator.INSTANCE);
|
||||
violations.add(index < 0 ? -index - 1 : index, violation);
|
||||
violationTree.addRuleViolation(violation);
|
||||
|
@ -6,7 +6,11 @@ package net.sourceforge.pmd;
|
||||
|
||||
/**
|
||||
* A RuleViolation is created by a Rule when it identifies a violation of the
|
||||
* Rule constraints.
|
||||
* Rule constraints. RuleViolations are simple data holders that are collected
|
||||
* into a {@link Report}.
|
||||
*
|
||||
* <p>Since PMD 6.21.0, implementations of this interface are considered internal
|
||||
* API and hence deprecated. Clients should exclusively use this interface.
|
||||
*
|
||||
* @see Rule
|
||||
*/
|
||||
@ -26,13 +30,6 @@ public interface RuleViolation {
|
||||
*/
|
||||
String getDescription();
|
||||
|
||||
/**
|
||||
* Indicates whether this violation has been suppressed.
|
||||
*
|
||||
* @return <code>true</code> if this violation is suppressed,
|
||||
* <code>false</code> otherwise.
|
||||
*/
|
||||
boolean isSuppressed();
|
||||
|
||||
/**
|
||||
* Get the source file name in which this violation was identified.
|
||||
|
@ -120,9 +120,7 @@ public class SourceCodeProcessor {
|
||||
|
||||
private Node parse(RuleContext ctx, Reader sourceCode, Parser parser) {
|
||||
try (TimedOperation to = TimeTracker.startOperation(TimedOperationCategory.PARSER)) {
|
||||
Node rootNode = parser.parse(String.valueOf(ctx.getSourceCodeFile()), sourceCode);
|
||||
ctx.getReport().suppress(parser.getSuppressMap());
|
||||
return rootNode;
|
||||
return parser.parse(String.valueOf(ctx.getSourceCodeFile()), sourceCode);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import net.sourceforge.pmd.Report.SuppressedViolation;
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.ast.RootNode;
|
||||
import net.sourceforge.pmd.lang.rule.RuleViolationFactory;
|
||||
|
||||
/**
|
||||
* An object that suppresses rule violations. Suppressors are used by
|
||||
* {@link RuleViolationFactory} to filter out violations. In PMD 6.0.x,
|
||||
* the {@link Report} object filtered violations itself - but it has
|
||||
* no knowledge of language-specific suppressors.
|
||||
*/
|
||||
public interface ViolationSuppressor {
|
||||
|
||||
/**
|
||||
* Suppressor for the violationSuppressRegex property.
|
||||
*/
|
||||
ViolationSuppressor REGEX_SUPPRESSOR = new ViolationSuppressor() {
|
||||
@Override
|
||||
public String getId() {
|
||||
return "Regex";
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable SuppressedViolation suppressOrNull(RuleViolation rv, @NonNull Node node) {
|
||||
String regex = rv.getRule().getProperty(Rule.VIOLATION_SUPPRESS_REGEX_DESCRIPTOR); // Regex
|
||||
if (regex != null && rv.getDescription() != null) {
|
||||
if (Pattern.matches(regex, rv.getDescription())) {
|
||||
return new SuppressedViolation(rv, this, regex);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Suppressor for the violationSuppressXPath property.
|
||||
*/
|
||||
ViolationSuppressor XPATH_SUPPRESSOR = new ViolationSuppressor() {
|
||||
@Override
|
||||
public String getId() {
|
||||
return "XPath";
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable SuppressedViolation suppressOrNull(RuleViolation rv, @NonNull Node node) {
|
||||
String xpath = rv.getRule().getProperty(Rule.VIOLATION_SUPPRESS_XPATH_DESCRIPTOR);
|
||||
if (xpath != null && node.hasDescendantMatchingXPath(xpath)) {
|
||||
return new SuppressedViolation(rv, this, xpath);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Suppressor for regular NOPMD comments.
|
||||
*
|
||||
* @implNote This requires special support from the language, namely
|
||||
* an implementation of {@link RootNode#getNoPmdComments()}.
|
||||
*/
|
||||
ViolationSuppressor NOPMD_COMMENT_SUPPRESSOR = new ViolationSuppressor() {
|
||||
@Override
|
||||
public String getId() {
|
||||
return "//NOPMD";
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable SuppressedViolation suppressOrNull(RuleViolation rv, @NonNull Node node) {
|
||||
Map<Integer, String> noPmd = node.getRoot().getNoPmdComments();
|
||||
if (noPmd.containsKey(rv.getBeginLine())) {
|
||||
return new SuppressedViolation(rv, this, noPmd.get(rv.getBeginLine()));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A name, for reporting and documentation purposes.
|
||||
*/
|
||||
String getId();
|
||||
|
||||
|
||||
/**
|
||||
* Returns a {@link SuppressedViolation} if the given violation is
|
||||
* suppressed by this object. The node and the rule are provided
|
||||
* for context. Returns null if the violation is not suppressed.
|
||||
*/
|
||||
@Nullable
|
||||
SuppressedViolation suppressOrNull(RuleViolation rv, @NonNull Node node);
|
||||
|
||||
|
||||
}
|
@ -69,11 +69,6 @@ public final class CachedRuleViolation implements RuleViolation {
|
||||
return description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSuppressed() {
|
||||
return false; // By definition, if cached, it was not suppressed
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFilename() {
|
||||
return fileName;
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
package net.sourceforge.pmd.lang;
|
||||
|
||||
import net.sourceforge.pmd.lang.ast.xpath.DefaultASTXPathHandler;
|
||||
import net.sourceforge.pmd.lang.dfa.DFAGraphRule;
|
||||
import net.sourceforge.pmd.lang.metrics.LanguageMetricsProvider;
|
||||
import net.sourceforge.pmd.util.designerbindings.DesignerBindings;
|
||||
@ -22,11 +21,6 @@ public abstract class AbstractLanguageVersionHandler implements LanguageVersionH
|
||||
return DataFlowHandler.DUMMY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XPathHandler getXPathHandler() {
|
||||
return new DefaultASTXPathHandler();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParserOptions getDefaultParserOptions() {
|
||||
return new ParserOptions();
|
||||
|
@ -12,6 +12,7 @@ import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.ServiceConfigurationError;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
@ -34,12 +35,17 @@ public final class LanguageRegistry {
|
||||
// Use current class' classloader instead of the threads context classloader, see https://github.com/pmd/pmd/issues/1377
|
||||
ServiceLoader<Language> languageLoader = ServiceLoader.load(Language.class, getClass().getClassLoader());
|
||||
Iterator<Language> iterator = languageLoader.iterator();
|
||||
//noinspection WhileLoopReplaceableByForEach -- https://youtrack.jetbrains.com/issue/IDEA-223743
|
||||
while (iterator.hasNext()) {
|
||||
while (true) {
|
||||
// this loop is weird, but both hasNext and next may throw ServiceConfigurationError,
|
||||
// it's more robust that way
|
||||
try {
|
||||
Language language = iterator.next();
|
||||
sortedLangs.add(language);
|
||||
} catch (UnsupportedClassVersionError e) {
|
||||
if (iterator.hasNext()) {
|
||||
Language language = iterator.next();
|
||||
sortedLangs.add(language);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} catch (UnsupportedClassVersionError | ServiceConfigurationError e) {
|
||||
// Some languages require java8 and are therefore only available
|
||||
// if java8 or later is used as runtime.
|
||||
System.err.println("Ignoring language for PMD: " + e.toString());
|
||||
|
@ -9,9 +9,11 @@ import java.util.List;
|
||||
import net.sourceforge.pmd.annotation.Experimental;
|
||||
import net.sourceforge.pmd.annotation.InternalApi;
|
||||
import net.sourceforge.pmd.lang.ast.AstProcessingStage;
|
||||
import net.sourceforge.pmd.lang.ast.xpath.DefaultASTXPathHandler;
|
||||
import net.sourceforge.pmd.lang.dfa.DFAGraphRule;
|
||||
import net.sourceforge.pmd.lang.metrics.LanguageMetricsProvider;
|
||||
import net.sourceforge.pmd.lang.rule.RuleViolationFactory;
|
||||
import net.sourceforge.pmd.lang.rule.impl.DefaultRuleViolationFactory;
|
||||
import net.sourceforge.pmd.util.designerbindings.DesignerBindings;
|
||||
import net.sourceforge.pmd.util.designerbindings.DesignerBindings.DefaultDesignerBindings;
|
||||
|
||||
@ -32,7 +34,9 @@ public interface LanguageVersionHandler {
|
||||
/**
|
||||
* Get the XPathHandler.
|
||||
*/
|
||||
XPathHandler getXPathHandler();
|
||||
default XPathHandler getXPathHandler() {
|
||||
return new DefaultASTXPathHandler();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@ -63,7 +67,9 @@ public interface LanguageVersionHandler {
|
||||
/**
|
||||
* Get the RuleViolationFactory.
|
||||
*/
|
||||
RuleViolationFactory getRuleViolationFactory();
|
||||
default RuleViolationFactory getRuleViolationFactory() {
|
||||
return DefaultRuleViolationFactory.defaultInstance();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
@ -5,7 +5,6 @@
|
||||
package net.sourceforge.pmd.lang;
|
||||
|
||||
import java.io.Reader;
|
||||
import java.util.Map;
|
||||
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.ast.ParseException;
|
||||
@ -47,21 +46,5 @@ public interface Parser {
|
||||
*/
|
||||
Node parse(String fileName, Reader source) throws ParseException;
|
||||
|
||||
/**
|
||||
* Returns the map of line numbers to suppression / review comments.
|
||||
* Only single line comments are considered, that start with the configured
|
||||
* "suppressMarker", which by default is "PMD". The text after the
|
||||
* suppressMarker is used as a "review comment" and included in this map.
|
||||
*
|
||||
* <p>
|
||||
* This map is later used to determine, if a violation is being suppressed.
|
||||
* It is suppressed, if the line of the violation is contained in this suppress map.
|
||||
*
|
||||
* @return map of the suppress lines with the corresponding review comments.
|
||||
*
|
||||
* @deprecated With 7.0.0, this method will be removed. To support
|
||||
* suppressing with suppress markers, this method is still needed in PMD 6.
|
||||
*/
|
||||
@Deprecated
|
||||
Map<Integer, String> getSuppressMap();
|
||||
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.jaxen.BaseXPath;
|
||||
import org.jaxen.JaxenException;
|
||||
import org.w3c.dom.Document;
|
||||
@ -397,4 +398,17 @@ public interface Node {
|
||||
default Iterator<Attribute> getXPathAttributesIterator() {
|
||||
return new AttributeAxisIterator(this);
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
default RootNode getRoot() {
|
||||
Node r = this;
|
||||
while (r != null && !(r instanceof RootNode)) {
|
||||
r = r.jjtGetParent();
|
||||
}
|
||||
if (r == null) {
|
||||
throw new IllegalStateException("No root node in tree ?");
|
||||
}
|
||||
return (RootNode) r;
|
||||
}
|
||||
}
|
||||
|
@ -4,13 +4,35 @@
|
||||
|
||||
package net.sourceforge.pmd.lang.ast;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import net.sourceforge.pmd.annotation.Experimental;
|
||||
import net.sourceforge.pmd.annotation.InternalApi;
|
||||
|
||||
/**
|
||||
* This interface can be used to tag the root node of various ASTs.
|
||||
*/
|
||||
public interface RootNode extends Node {
|
||||
// that's only a marker interface.
|
||||
// TODO we could add some utilities here eg to get the file name,
|
||||
// the language of the node,
|
||||
// the source code of the file (as recently done in PLSQL - #1728),
|
||||
// the whole token chain, etc
|
||||
|
||||
|
||||
/**
|
||||
* Returns the map of line numbers to suppression / review comments.
|
||||
* Only single line comments are considered, that start with the configured
|
||||
* "suppressMarker", which by default is "PMD". The text after the
|
||||
* suppressMarker is used as a "review comment" and included in this map.
|
||||
*
|
||||
* <p>
|
||||
* This map is later used to determine, if a violation is being suppressed.
|
||||
* It is suppressed, if the line of the violation is contained in this suppress map.
|
||||
*
|
||||
* @return map of the suppress lines with the corresponding review comments.
|
||||
*/
|
||||
@InternalApi
|
||||
@Experimental
|
||||
default Map<Integer, String> getNoPmdComments() {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -6,8 +6,6 @@ package net.sourceforge.pmd.lang.ast.impl.antlr4;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.antlr.v4.runtime.Lexer;
|
||||
|
||||
@ -51,11 +49,6 @@ public abstract class AntlrBaseParser<T extends org.antlr.v4.runtime.Parser> imp
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Integer, String> getSuppressMap() {
|
||||
return new HashMap<>();
|
||||
}
|
||||
|
||||
protected abstract AntlrBaseNode getRootNode(T parser);
|
||||
|
||||
protected abstract Lexer getLexer(Reader source) throws IOException;
|
||||
|
@ -1,35 +0,0 @@
|
||||
/*
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.ast.impl.antlr4;
|
||||
|
||||
import net.sourceforge.pmd.Rule;
|
||||
import net.sourceforge.pmd.RuleContext;
|
||||
import net.sourceforge.pmd.RuleViolation;
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.rule.AbstractRuleViolationFactory;
|
||||
import net.sourceforge.pmd.lang.rule.ParametricRuleViolation;
|
||||
import net.sourceforge.pmd.lang.rule.RuleViolationFactory;
|
||||
|
||||
public final class AntlrRuleViolationFactory extends AbstractRuleViolationFactory {
|
||||
public static final RuleViolationFactory INSTANCE = new AntlrRuleViolationFactory();
|
||||
|
||||
private AntlrRuleViolationFactory() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RuleViolation createRuleViolation(final Rule rule, final RuleContext ruleContext, final Node node,
|
||||
final String message) {
|
||||
return new ParametricRuleViolation<>(rule, ruleContext, (AntlrBaseNode) node, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RuleViolation createRuleViolation(final Rule rule, final RuleContext ruleContext, final Node node,
|
||||
final String message, final int beginLine, final int endLine) {
|
||||
final ParametricRuleViolation<AntlrBaseNode> violation = new ParametricRuleViolation<>(rule, ruleContext,
|
||||
(AntlrBaseNode) node, message);
|
||||
violation.setLines(beginLine, endLine);
|
||||
return violation;
|
||||
}
|
||||
}
|
@ -1,54 +1,15 @@
|
||||
/**
|
||||
/*
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.rule;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import net.sourceforge.pmd.lang.rule.impl.DefaultRuleViolationFactory;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import net.sourceforge.pmd.Rule;
|
||||
import net.sourceforge.pmd.RuleContext;
|
||||
import net.sourceforge.pmd.RuleViolation;
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
|
||||
public abstract class AbstractRuleViolationFactory implements RuleViolationFactory {
|
||||
|
||||
private static final Object[] NO_ARGS = new Object[0];
|
||||
|
||||
private String cleanup(String message, Object[] args) {
|
||||
|
||||
if (message != null) {
|
||||
// Escape PMD specific variable message format, specifically the {
|
||||
// in the ${, so MessageFormat doesn't bitch.
|
||||
final String escapedMessage = StringUtils.replace(message, "${", "$'{'");
|
||||
return MessageFormat.format(escapedMessage, args != null ? args : NO_ARGS);
|
||||
} else {
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addViolation(RuleContext ruleContext, Rule rule, Node node, String message, Object[] args) {
|
||||
|
||||
String formattedMessage = cleanup(message, args);
|
||||
|
||||
ruleContext.getReport().addRuleViolation(createRuleViolation(rule, ruleContext, node, formattedMessage));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addViolation(RuleContext ruleContext, Rule rule, Node node, String message, int beginLine, int endLine,
|
||||
Object[] args) {
|
||||
|
||||
String formattedMessage = cleanup(message, args);
|
||||
|
||||
ruleContext.getReport()
|
||||
.addRuleViolation(createRuleViolation(rule, ruleContext, node, formattedMessage, beginLine, endLine));
|
||||
}
|
||||
|
||||
protected abstract RuleViolation createRuleViolation(Rule rule, RuleContext ruleContext, Node node, String message);
|
||||
|
||||
protected abstract RuleViolation createRuleViolation(Rule rule, RuleContext ruleContext, Node node, String message,
|
||||
int beginLine, int endLine);
|
||||
/**
|
||||
* @deprecated This is kept for binary compatibility with the 6.x designer, yet will
|
||||
* go away in 7.0. Use {@link DefaultRuleViolationFactory}
|
||||
*/
|
||||
@Deprecated
|
||||
public class AbstractRuleViolationFactory extends DefaultRuleViolationFactory {
|
||||
}
|
||||
|
@ -5,7 +5,6 @@
|
||||
package net.sourceforge.pmd.lang.rule;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import net.sourceforge.pmd.Rule;
|
||||
import net.sourceforge.pmd.RuleContext;
|
||||
@ -18,7 +17,6 @@ public class ParametricRuleViolation<T extends Node> implements RuleViolation {
|
||||
|
||||
protected final Rule rule;
|
||||
protected final String description;
|
||||
protected boolean suppressed;
|
||||
protected String filename;
|
||||
|
||||
protected int beginLine;
|
||||
@ -36,6 +34,7 @@ public class ParametricRuleViolation<T extends Node> implements RuleViolation {
|
||||
// must not (to prevent erroneous Rules silently logging w/o a Node). Modify
|
||||
// RuleViolationFactory to support identifying without a Node, and update
|
||||
// Rule base classes too.
|
||||
// TODO we never need a node. We just have to have a "position", ie line/column, or offset, + file, whatever
|
||||
public ParametricRuleViolation(Rule theRule, RuleContext ctx, T node, String message) {
|
||||
rule = theRule;
|
||||
description = message;
|
||||
@ -53,28 +52,6 @@ public class ParametricRuleViolation<T extends Node> implements RuleViolation {
|
||||
endColumn = node.getEndColumn();
|
||||
}
|
||||
|
||||
// Apply Rule specific suppressions
|
||||
if (node != null && rule != null) {
|
||||
setSuppression(rule, node);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void setSuppression(Rule rule, T node) {
|
||||
|
||||
String regex = rule.getProperty(Rule.VIOLATION_SUPPRESS_REGEX_DESCRIPTOR); // Regex
|
||||
if (regex != null && description != null) {
|
||||
if (Pattern.matches(regex, description)) {
|
||||
suppressed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!suppressed) { // XPath
|
||||
String xpath = rule.getProperty(Rule.VIOLATION_SUPPRESS_XPATH_DESCRIPTOR);
|
||||
if (xpath != null) {
|
||||
suppressed = node.hasDescendantMatchingXPath(xpath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected String expandVariables(String message) {
|
||||
@ -127,11 +104,6 @@ public class ParametricRuleViolation<T extends Node> implements RuleViolation {
|
||||
return expandVariables(description);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSuppressed() {
|
||||
return suppressed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFilename() {
|
||||
return filename;
|
||||
|
@ -4,13 +4,20 @@
|
||||
|
||||
package net.sourceforge.pmd.lang.rule;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import net.sourceforge.pmd.Rule;
|
||||
import net.sourceforge.pmd.RuleContext;
|
||||
import net.sourceforge.pmd.lang.LanguageVersionHandler;
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
|
||||
/**
|
||||
* This class handles of producing a Language specific RuleViolation and adding
|
||||
* to a Report.
|
||||
*
|
||||
* <p>Since PMD 6.21.0, implementations of this interface are considered internal
|
||||
* API and hence deprecated. Clients should exclusively use this interface and obtain
|
||||
* instances through {@link LanguageVersionHandler#getRuleViolationFactory()}.
|
||||
*/
|
||||
public interface RuleViolationFactory {
|
||||
/**
|
||||
@ -27,8 +34,8 @@ public interface RuleViolationFactory {
|
||||
* @param args
|
||||
* arguments to embed in the rule violation message
|
||||
*/
|
||||
void addViolation(RuleContext ruleContext, Rule rule, Node node, String message, Object[] args);
|
||||
void addViolation(RuleContext ruleContext, Rule rule, @Nullable Node node, String message, Object[] args);
|
||||
|
||||
void addViolation(RuleContext ruleContext, Rule rule, Node node, String message, int beginLine, int endLine,
|
||||
Object[] args);
|
||||
|
||||
void addViolation(RuleContext ruleContext, Rule rule, @Nullable Node node, String message, int beginLine, int endLine, Object[] args);
|
||||
}
|
||||
|
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.rule.impl;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import net.sourceforge.pmd.Report.SuppressedViolation;
|
||||
import net.sourceforge.pmd.Rule;
|
||||
import net.sourceforge.pmd.RuleContext;
|
||||
import net.sourceforge.pmd.RuleViolation;
|
||||
import net.sourceforge.pmd.ViolationSuppressor;
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.rule.ParametricRuleViolation;
|
||||
import net.sourceforge.pmd.lang.rule.RuleViolationFactory;
|
||||
|
||||
/**
|
||||
* This is a functional implementation of {@link RuleViolationFactory}.
|
||||
* It uses only the standard {@link ViolationSuppressor}s (constants in the interface).
|
||||
* It may be extended to add more suppression options.
|
||||
*
|
||||
* <p>Implementations should be internal. Only the interface should be exposed.
|
||||
*/
|
||||
public class DefaultRuleViolationFactory implements RuleViolationFactory {
|
||||
|
||||
private static final Object[] NO_ARGS = new Object[0];
|
||||
|
||||
private static final DefaultRuleViolationFactory DEFAULT = new DefaultRuleViolationFactory();
|
||||
private Set<ViolationSuppressor> allSuppressors;
|
||||
|
||||
private String cleanup(String message, Object[] args) {
|
||||
|
||||
if (message != null) {
|
||||
// Escape PMD specific variable message format, specifically the {
|
||||
// in the ${, so MessageFormat doesn't bitch.
|
||||
final String escapedMessage = StringUtils.replace(message, "${", "$'{'");
|
||||
return MessageFormat.format(escapedMessage, args != null ? args : NO_ARGS);
|
||||
} else {
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void addViolation(RuleContext ruleContext, Rule rule, Node node, String message, Object[] args) {
|
||||
|
||||
String formattedMessage = cleanup(message, args);
|
||||
|
||||
RuleViolation rv = createRuleViolation(rule, ruleContext, node, formattedMessage);
|
||||
maybeSuppress(ruleContext, node, rv);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addViolation(RuleContext ruleContext, Rule rule, Node node, String message, int beginLine, int endLine, Object[] args) {
|
||||
|
||||
String formattedMessage = cleanup(message, args);
|
||||
|
||||
RuleViolation rv = createRuleViolation(rule, ruleContext, node, formattedMessage, beginLine, endLine);
|
||||
maybeSuppress(ruleContext, node, rv);
|
||||
}
|
||||
|
||||
private void maybeSuppress(RuleContext ruleContext, @Nullable Node node, RuleViolation rv) {
|
||||
|
||||
if (node != null) {
|
||||
// note: no suppression when node is null.
|
||||
// Node should in fact never be null, this is todo for later
|
||||
|
||||
for (ViolationSuppressor suppressor : getAllSuppressors()) {
|
||||
SuppressedViolation suppressed = suppressor.suppressOrNull(rv, node);
|
||||
if (suppressed != null) {
|
||||
ruleContext.getReport().addSuppressedViolation(suppressed);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ruleContext.getReport().addRuleViolation(rv);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of additional suppressors for this language. These
|
||||
* are added to regular //NOPMD, regex and XPath suppression.
|
||||
*/
|
||||
protected List<ViolationSuppressor> getSuppressors() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
protected RuleViolation createRuleViolation(Rule rule, RuleContext ruleContext, Node node, String message) {
|
||||
return new ParametricRuleViolation<>(rule, ruleContext, node, message);
|
||||
}
|
||||
|
||||
protected RuleViolation createRuleViolation(Rule rule, RuleContext ruleContext, Node node, String message,
|
||||
int beginLine, int endLine) {
|
||||
ParametricRuleViolation<Node> rv = new ParametricRuleViolation<>(rule, ruleContext, node, message);
|
||||
rv.setLines(beginLine, endLine);
|
||||
return rv;
|
||||
}
|
||||
|
||||
private Set<ViolationSuppressor> getAllSuppressors() {
|
||||
if (allSuppressors == null) {
|
||||
// lazy loaded because calling getSuppressors in constructor
|
||||
// is not safe wrt initialization of static constants
|
||||
// (order dependent otherwise)
|
||||
this.allSuppressors = new LinkedHashSet<>(getSuppressors());
|
||||
allSuppressors.add(ViolationSuppressor.NOPMD_COMMENT_SUPPRESSOR);
|
||||
allSuppressors.add(ViolationSuppressor.REGEX_SUPPRESSOR);
|
||||
allSuppressors.add(ViolationSuppressor.XPATH_SUPPRESSOR);
|
||||
}
|
||||
return allSuppressors;
|
||||
}
|
||||
|
||||
/** Returns the default instance (no additional suppressors, creates a ParametricRuleViolation). */
|
||||
public static RuleViolationFactory defaultInstance() {
|
||||
return DEFAULT;
|
||||
}
|
||||
}
|
@ -113,13 +113,13 @@ public class HTMLRenderer extends AbstractIncrementingRenderer {
|
||||
buf.append(" bgcolor=\"lightgrey\"");
|
||||
}
|
||||
colorize = !colorize;
|
||||
buf.append("> " + PMD.EOL);
|
||||
buf.append("<td align=\"center\">" + violationCount + "</td>" + PMD.EOL);
|
||||
buf.append("<td width=\"*%\">"
|
||||
+ maybeWrap(StringEscapeUtils.escapeHtml4(determineFileName(rv.getFilename())),
|
||||
linePrefix == null ? "" : linePrefix + Integer.toString(rv.getBeginLine()))
|
||||
+ "</td>" + PMD.EOL);
|
||||
buf.append("<td align=\"center\" width=\"5%\">" + Integer.toString(rv.getBeginLine()) + "</td>" + PMD.EOL);
|
||||
buf.append("> ").append(PMD.EOL);
|
||||
buf.append("<td align=\"center\">").append(violationCount).append("</td>").append(PMD.EOL);
|
||||
buf.append("<td width=\"*%\">")
|
||||
.append(maybeWrap(StringEscapeUtils.escapeHtml4(determineFileName(rv.getFilename())), linePrefix == null ? "" : linePrefix + rv.getBeginLine()))
|
||||
.append("</td>")
|
||||
.append(PMD.EOL);
|
||||
buf.append("<td align=\"center\" width=\"5%\">").append(rv.getBeginLine()).append("</td>").append(PMD.EOL);
|
||||
|
||||
String d = StringEscapeUtils.escapeHtml4(rv.getDescription());
|
||||
|
||||
@ -127,8 +127,11 @@ public class HTMLRenderer extends AbstractIncrementingRenderer {
|
||||
if (StringUtils.isNotBlank(infoUrl)) {
|
||||
d = "<a href=\"" + infoUrl + "\">" + d + "</a>";
|
||||
}
|
||||
buf.append("<td width=\"*\">" + d + "</td>" + PMD.EOL);
|
||||
buf.append("</tr>" + PMD.EOL);
|
||||
buf.append("<td width=\"*\">")
|
||||
.append(d)
|
||||
.append("</td>")
|
||||
.append(PMD.EOL)
|
||||
.append("</tr>").append(PMD.EOL);
|
||||
writer.write(buf.toString());
|
||||
violationCount++;
|
||||
}
|
||||
@ -154,10 +157,10 @@ public class HTMLRenderer extends AbstractIncrementingRenderer {
|
||||
buf.append(" bgcolor=\"lightgrey\"");
|
||||
}
|
||||
colorize = !colorize;
|
||||
buf.append("> " + PMD.EOL);
|
||||
buf.append("<td>" + determineFileName(pe.getFile()) + "</td>" + PMD.EOL);
|
||||
buf.append("<td><pre>" + pe.getDetail() + "</pre></td>" + PMD.EOL);
|
||||
buf.append("</tr>" + PMD.EOL);
|
||||
buf.append("> ").append(PMD.EOL);
|
||||
buf.append("<td>").append(determineFileName(pe.getFile())).append("</td>").append(PMD.EOL);
|
||||
buf.append("<td><pre>").append(pe.getDetail()).append("</pre></td>").append(PMD.EOL);
|
||||
buf.append("</tr>").append(PMD.EOL);
|
||||
writer.write(buf.toString());
|
||||
}
|
||||
writer.write("</table>");
|
||||
@ -182,19 +185,19 @@ public class HTMLRenderer extends AbstractIncrementingRenderer {
|
||||
buf.append(" bgcolor=\"lightgrey\"");
|
||||
}
|
||||
colorize = !colorize;
|
||||
buf.append("> " + PMD.EOL);
|
||||
buf.append("<td align=\"left\">" + determineFileName(sv.getRuleViolation().getFilename()) + "</td>" + PMD.EOL);
|
||||
buf.append("<td align=\"center\">" + sv.getRuleViolation().getBeginLine() + "</td>" + PMD.EOL);
|
||||
buf.append("<td align=\"center\">" + sv.getRuleViolation().getRule().getName() + "</td>" + PMD.EOL);
|
||||
buf.append("<td align=\"center\">" + (sv.suppressedByNOPMD() ? "NOPMD" : "Annotation") + "</td>" + PMD.EOL);
|
||||
buf.append("<td align=\"center\">" + (sv.getUserMessage() == null ? "" : sv.getUserMessage()) + "</td>"
|
||||
+ PMD.EOL);
|
||||
buf.append("</tr>" + PMD.EOL);
|
||||
buf.append("> ").append(PMD.EOL);
|
||||
buf.append("<td align=\"left\">").append(determineFileName(sv.getRuleViolation().getFilename())).append("</td>").append(PMD.EOL);
|
||||
buf.append("<td align=\"center\">").append(sv.getRuleViolation().getBeginLine()).append("</td>").append(PMD.EOL);
|
||||
buf.append("<td align=\"center\">").append(sv.getRuleViolation().getRule().getName()).append("</td>").append(PMD.EOL);
|
||||
buf.append("<td align=\"center\">").append(sv.getSuppressor().getId()).append("</td>").append(PMD.EOL);
|
||||
buf.append("<td align=\"center\">").append(
|
||||
sv.getUserMessage() == null ? "" : sv.getUserMessage()).append("</td>").append(PMD.EOL);
|
||||
buf.append("</tr>").append(PMD.EOL);
|
||||
writer.write(buf.toString());
|
||||
}
|
||||
writer.write("</table>");
|
||||
}
|
||||
|
||||
|
||||
private void glomConfigurationErrors(final Writer writer, final List<ConfigurationError> configErrors) throws IOException {
|
||||
if (configErrors.isEmpty()) {
|
||||
return;
|
||||
@ -214,10 +217,10 @@ public class HTMLRenderer extends AbstractIncrementingRenderer {
|
||||
buf.append(" bgcolor=\"lightgrey\"");
|
||||
}
|
||||
colorize = !colorize;
|
||||
buf.append("> " + PMD.EOL);
|
||||
buf.append("<td>" + ce.rule().getName() + "</td>" + PMD.EOL);
|
||||
buf.append("<td>" + ce.issue() + "</td>" + PMD.EOL);
|
||||
buf.append("</tr>" + PMD.EOL);
|
||||
buf.append("> ").append(PMD.EOL);
|
||||
buf.append("<td>").append(ce.rule().getName()).append("</td>").append(PMD.EOL);
|
||||
buf.append("<td>").append(ce.issue()).append("</td>").append(PMD.EOL);
|
||||
buf.append("</tr>").append(PMD.EOL);
|
||||
writer.write(buf.toString());
|
||||
}
|
||||
writer.write("</table>");
|
||||
|
@ -35,7 +35,7 @@ public class TextRenderer extends AbstractIncrementingRenderer {
|
||||
buf.setLength(0);
|
||||
RuleViolation rv = violations.next();
|
||||
buf.append(determineFileName(rv.getFilename()));
|
||||
buf.append(':').append(Integer.toString(rv.getBeginLine()));
|
||||
buf.append(':').append(rv.getBeginLine());
|
||||
buf.append(":\t").append(rv.getDescription()).append(PMD.EOL);
|
||||
writer.write(buf.toString());
|
||||
}
|
||||
@ -44,7 +44,7 @@ public class TextRenderer extends AbstractIncrementingRenderer {
|
||||
@Override
|
||||
public void end() throws IOException {
|
||||
StringBuilder buf = new StringBuilder(500);
|
||||
|
||||
|
||||
for (Report.ProcessingError error : errors) {
|
||||
buf.setLength(0);
|
||||
buf.append(determineFileName(error.getFile()));
|
||||
@ -54,13 +54,15 @@ public class TextRenderer extends AbstractIncrementingRenderer {
|
||||
|
||||
for (Report.SuppressedViolation excluded : suppressed) {
|
||||
buf.setLength(0);
|
||||
buf.append(excluded.getRuleViolation().getRule().getName());
|
||||
buf.append(" rule violation suppressed by ");
|
||||
buf.append(excluded.suppressedByNOPMD() ? "//NOPMD" : "Annotation");
|
||||
buf.append(" in ").append(determineFileName(excluded.getRuleViolation().getFilename())).append(PMD.EOL);
|
||||
buf.append(excluded.getRuleViolation().getRule().getName())
|
||||
.append(" rule violation suppressed by ")
|
||||
.append(excluded.getSuppressor().getId())
|
||||
.append(" in ")
|
||||
.append(determineFileName(excluded.getRuleViolation().getFilename()))
|
||||
.append(PMD.EOL);
|
||||
writer.write(buf.toString());
|
||||
}
|
||||
|
||||
|
||||
for (Report.ConfigurationError error : configErrors) {
|
||||
buf.setLength(0);
|
||||
buf.append(error.rule().getName());
|
||||
|
@ -8,6 +8,7 @@ import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.Locale;
|
||||
|
||||
import net.sourceforge.pmd.PMD;
|
||||
import net.sourceforge.pmd.PMDVersion;
|
||||
@ -135,7 +136,7 @@ public class XMLRenderer extends AbstractIncrementingRenderer {
|
||||
buf.append("<suppressedviolation ").append("filename=\"");
|
||||
StringUtil.appendXmlEscaped(buf, determineFileName(s.getRuleViolation().getFilename()), useUTF8);
|
||||
buf.append("\" suppressiontype=\"");
|
||||
StringUtil.appendXmlEscaped(buf, s.suppressedByNOPMD() ? "nopmd" : "annotation", useUTF8);
|
||||
StringUtil.appendXmlEscaped(buf, s.getSuppressor().getId().toLowerCase(Locale.ROOT), useUTF8);
|
||||
buf.append("\" msg=\"");
|
||||
StringUtil.appendXmlEscaped(buf, s.getRuleViolation().getDescription(), useUTF8);
|
||||
buf.append("\" usermsg=\"");
|
||||
@ -144,7 +145,7 @@ public class XMLRenderer extends AbstractIncrementingRenderer {
|
||||
writer.write(buf.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// config errors
|
||||
for (final Report.ConfigurationError ce : configErrors) {
|
||||
buf.setLength(0);
|
||||
|
@ -19,9 +19,11 @@ import org.junit.Test;
|
||||
import net.sourceforge.pmd.lang.DummyLanguageModule;
|
||||
import net.sourceforge.pmd.lang.LanguageRegistry;
|
||||
import net.sourceforge.pmd.lang.ast.DummyNode;
|
||||
import net.sourceforge.pmd.lang.ast.DummyRoot;
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.rule.AbstractRule;
|
||||
import net.sourceforge.pmd.lang.rule.ParametricRuleViolation;
|
||||
import net.sourceforge.pmd.lang.rule.impl.DefaultRuleViolationFactory;
|
||||
import net.sourceforge.pmd.properties.PropertyDescriptor;
|
||||
import net.sourceforge.pmd.properties.PropertyFactory;
|
||||
import net.sourceforge.pmd.properties.StringProperty;
|
||||
@ -110,9 +112,8 @@ public class AbstractRuleTest {
|
||||
ctx.setLanguageVersion(LanguageRegistry.getLanguage(DummyLanguageModule.NAME).getDefaultVersion());
|
||||
ctx.setReport(new Report());
|
||||
ctx.setSourceCodeFile(new File("filename"));
|
||||
DummyNode s = new DummyNode(1);
|
||||
s.testingOnlySetBeginColumn(5);
|
||||
s.testingOnlySetBeginLine(5);
|
||||
DummyNode s = new DummyRoot();
|
||||
s.setCoords(5, 1, 6, 0);
|
||||
s.setImage("TestImage");
|
||||
r.addViolation(ctx, s);
|
||||
RuleViolation rv = ctx.getReport().getViolationTree().iterator().next();
|
||||
@ -124,15 +125,12 @@ public class AbstractRuleTest {
|
||||
MyRule r = new MyRule();
|
||||
RuleContext ctx = new RuleContext();
|
||||
Map<Integer, String> m = new HashMap<>();
|
||||
m.put(Integer.valueOf(5), "");
|
||||
ctx.setReport(new Report());
|
||||
ctx.getReport().suppress(m);
|
||||
m.put(5, "");
|
||||
ctx.setSourceCodeFile(new File("filename"));
|
||||
DummyNode n = new DummyNode(1);
|
||||
n.testingOnlySetBeginColumn(5);
|
||||
n.testingOnlySetBeginLine(5);
|
||||
RuleViolation rv = new ParametricRuleViolation<>(r, ctx, n, "specificdescription");
|
||||
ctx.getReport().addRuleViolation(rv);
|
||||
DummyRoot n = new DummyRoot(m);
|
||||
n.setCoords(5, 1, 6, 0);
|
||||
DefaultRuleViolationFactory.defaultInstance().addViolation(ctx, r, n, "specificdescription", new Object[0]);
|
||||
|
||||
assertTrue(ctx.getReport().isEmpty());
|
||||
}
|
||||
|
||||
@ -210,7 +208,7 @@ public class AbstractRuleTest {
|
||||
assertEquals("Rules with different messages are still equal", r1, r2);
|
||||
assertEquals("Rules that are equal must have the an equal hashcode", r1.hashCode(), r2.hashCode());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testDeepCopyRule() {
|
||||
MyRule r1 = new MyRule();
|
||||
|
@ -30,6 +30,7 @@ import net.sourceforge.pmd.lang.Dummy2LanguageModule;
|
||||
import net.sourceforge.pmd.lang.DummyLanguageModule;
|
||||
import net.sourceforge.pmd.lang.LanguageRegistry;
|
||||
import net.sourceforge.pmd.lang.ast.DummyNode;
|
||||
import net.sourceforge.pmd.lang.ast.DummyRoot;
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.rule.MockRule;
|
||||
import net.sourceforge.pmd.lang.rule.RuleReference;
|
||||
@ -501,9 +502,8 @@ public class RuleSetTest {
|
||||
|
||||
private List<Node> makeCompilationUnits() {
|
||||
List<Node> nodes = new ArrayList<>();
|
||||
DummyNode node = new DummyNode(1);
|
||||
node.testingOnlySetBeginLine(1);
|
||||
node.testingOnlySetBeginColumn(1);
|
||||
DummyNode node = new DummyRoot();
|
||||
node.setCoords(1, 1, 10, 1);
|
||||
node.setImage("Foo");
|
||||
nodes.add(node);
|
||||
return nodes;
|
||||
|
@ -7,21 +7,19 @@ package net.sourceforge.pmd.lang;
|
||||
import java.io.Reader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.sourceforge.pmd.Rule;
|
||||
import net.sourceforge.pmd.RuleContext;
|
||||
import net.sourceforge.pmd.RuleViolation;
|
||||
import net.sourceforge.pmd.lang.ast.DummyAstStages;
|
||||
import net.sourceforge.pmd.lang.ast.DummyNode;
|
||||
import net.sourceforge.pmd.lang.ast.DummyRoot;
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.ast.ParseException;
|
||||
import net.sourceforge.pmd.lang.ast.RootNode;
|
||||
import net.sourceforge.pmd.lang.rule.AbstractRuleChainVisitor;
|
||||
import net.sourceforge.pmd.lang.rule.AbstractRuleViolationFactory;
|
||||
import net.sourceforge.pmd.lang.rule.ParametricRuleViolation;
|
||||
import net.sourceforge.pmd.lang.rule.impl.DefaultRuleViolationFactory;
|
||||
|
||||
/**
|
||||
* Dummy language used for testing PMD.
|
||||
@ -80,18 +78,12 @@ public class DummyLanguageModule extends BaseLanguageModule {
|
||||
return new AbstractParser(parserOptions) {
|
||||
@Override
|
||||
public Node parse(String fileName, Reader source) throws ParseException {
|
||||
DummyNode node = new DummyRootNode(1);
|
||||
node.testingOnlySetBeginLine(1);
|
||||
node.testingOnlySetBeginColumn(1);
|
||||
DummyNode node = new DummyRoot();
|
||||
node.setCoords(1, 1, 2, 10);
|
||||
node.setImage("Foo");
|
||||
return node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Integer, String> getSuppressMap() {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TokenManager createTokenManager(Reader source) {
|
||||
return null;
|
||||
@ -100,15 +92,7 @@ public class DummyLanguageModule extends BaseLanguageModule {
|
||||
}
|
||||
}
|
||||
|
||||
private static class DummyRootNode extends DummyNode implements RootNode {
|
||||
|
||||
DummyRootNode(int id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class RuleViolationFactory extends AbstractRuleViolationFactory {
|
||||
public static class RuleViolationFactory extends DefaultRuleViolationFactory {
|
||||
@Override
|
||||
protected RuleViolation createRuleViolation(Rule rule, RuleContext ruleContext, Node node, String message) {
|
||||
return createRuleViolation(rule, ruleContext, node, message, 0, 0);
|
||||
@ -118,6 +102,7 @@ public class DummyLanguageModule extends BaseLanguageModule {
|
||||
protected RuleViolation createRuleViolation(Rule rule, RuleContext ruleContext, Node node, String message,
|
||||
int beginLine, int endLine) {
|
||||
ParametricRuleViolation<Node> rv = new ParametricRuleViolation<Node>(rule, ruleContext, node, message) {
|
||||
@Override
|
||||
public String getPackageName() {
|
||||
this.packageName = "foo"; // just for testing variable expansion
|
||||
return super.getPackageName();
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user