Merge branch '7.0.x' into java-rule-bulk-update
This commit is contained in:
commit
c1e58ad5e7
7 files changed
+199
-2
No files matched your search
@@ -33,6 +33,9 @@ This is a {{ site.pmd.release_type }} release.
|
||||
{% jdoc !!java::lang.java.ast.ASTTypeParameter#getParameterName() %}
|
||||
and the corresponding XPath attributes. In both cases they're replaced with a new method `getName`,
|
||||
the attribute is `@Name`.
|
||||
* {% jdoc !!java::lang.java.ast.ASTClassOrInterfaceBody#isAnonymousInnerClass() %},
|
||||
and {% jdoc !!java::lang.java.ast.ASTClassOrInterfaceBody#isEnumChild() %},
|
||||
refs [#905](https://github.com/pmd/pmd/issues/905)
|
||||
|
||||
#### Internal API
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ 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.internal.SystemProps;
|
||||
import net.sourceforge.pmd.lang.LanguageVersion;
|
||||
import net.sourceforge.pmd.lang.Parser;
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
@@ -105,9 +106,15 @@ public class SourceCodeProcessor {
|
||||
} catch (ParseException pe) {
|
||||
configuration.getAnalysisCache().analysisFailed(ctx.getSourceCodeFile());
|
||||
throw new PMDException("Error while parsing " + ctx.getSourceCodeFile(), pe);
|
||||
} catch (Exception | StackOverflowError | AssertionError e) {
|
||||
} catch (Exception e) {
|
||||
configuration.getAnalysisCache().analysisFailed(ctx.getSourceCodeFile());
|
||||
throw new PMDException("Error while processing " + ctx.getSourceCodeFile(), e);
|
||||
} catch (StackOverflowError | AssertionError e) {
|
||||
if (SystemProps.isErrorRecoveryMode()) {
|
||||
configuration.getAnalysisCache().analysisFailed(ctx.getSourceCodeFile());
|
||||
throw new PMDException("Error while processing " + ctx.getSourceCodeFile(), e);
|
||||
}
|
||||
throw e;
|
||||
} finally {
|
||||
ruleSets.end(ctx);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.internal;
|
||||
|
||||
public final class SystemProps {
|
||||
|
||||
public static final String PMD_ERROR_RECOVERY = "pmd.error_recovery";
|
||||
|
||||
private SystemProps() {
|
||||
}
|
||||
|
||||
/**
|
||||
* In error recovery mode errors like StackOverflowError or AssertionErrors are logged
|
||||
* and the execution continues.
|
||||
* These exceptions mean, that something went really wrong while executing and
|
||||
* depending on where the error occurred, the internal state might be corrupted
|
||||
* or not. Hence, it might work to continue and "ignore" (just log) the error
|
||||
* or we'll see more problems when continuing. That's why error recovery mode
|
||||
* is not enabled by default.
|
||||
* <p>
|
||||
* The System Property is called {@code pmd.error_recovery}.
|
||||
*/
|
||||
public static boolean isErrorRecoveryMode() {
|
||||
return System.getProperty(PMD_ERROR_RECOVERY) != null;
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ import net.sourceforge.pmd.RuleSet;
|
||||
import net.sourceforge.pmd.benchmark.TimeTracker;
|
||||
import net.sourceforge.pmd.benchmark.TimedOperation;
|
||||
import net.sourceforge.pmd.benchmark.TimedOperationCategory;
|
||||
import net.sourceforge.pmd.internal.SystemProps;
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
|
||||
/** Applies a set of rules to a set of ASTs. */
|
||||
@@ -60,10 +61,21 @@ public class RuleApplicator {
|
||||
try (TimedOperation rcto = TimeTracker.startOperation(TimedOperationCategory.RULE, rule.getName())) {
|
||||
rule.apply(node, ctx);
|
||||
rcto.close(1);
|
||||
} catch (RuntimeException | StackOverflowError | AssertionError e) {
|
||||
} catch (RuntimeException e) {
|
||||
if (ctx.isIgnoreExceptions()) {
|
||||
ctx.getReport().addError(new ProcessingError(e, String.valueOf(ctx.getSourceCodeFile())));
|
||||
|
||||
if (LOG.isLoggable(Level.WARNING)) {
|
||||
LOG.log(Level.WARNING, "Exception applying rule " + rule.getName() + " on file "
|
||||
+ ctx.getSourceCodeFile() + ", continuing with next rule", e);
|
||||
}
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
} catch (StackOverflowError | AssertionError e) {
|
||||
if (SystemProps.isErrorRecoveryMode()) {
|
||||
ctx.getReport().addError(new ProcessingError(e, String.valueOf(ctx.getSourceCodeFile())));
|
||||
|
||||
if (LOG.isLoggable(Level.WARNING)) {
|
||||
LOG.log(Level.WARNING, "Exception applying rule " + rule.getName() + " on file "
|
||||
+ ctx.getSourceCodeFile() + ", continuing with next rule", e);
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.contrib.java.lang.system.RestoreSystemProperties;
|
||||
import org.junit.rules.TestRule;
|
||||
|
||||
import net.sourceforge.pmd.internal.SystemProps;
|
||||
import net.sourceforge.pmd.lang.DummyLanguageModule;
|
||||
import net.sourceforge.pmd.lang.Language;
|
||||
import net.sourceforge.pmd.lang.LanguageRegistry;
|
||||
import net.sourceforge.pmd.lang.LanguageVersion;
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.rule.AbstractRule;
|
||||
|
||||
public class SourceCodeProcessorTest {
|
||||
|
||||
@org.junit.Rule
|
||||
public TestRule restoreSystemProperties = new RestoreSystemProperties();
|
||||
|
||||
private SourceCodeProcessor processor;
|
||||
private StringReader sourceCode;
|
||||
private RuleContext ctx;
|
||||
private List<RuleSet> rulesets;
|
||||
private LanguageVersion dummyThrows;
|
||||
private LanguageVersion dummyDefault;
|
||||
|
||||
@Before
|
||||
public void prepare() {
|
||||
Language dummyLanguage = LanguageRegistry.findLanguageByTerseName(DummyLanguageModule.TERSE_NAME);
|
||||
dummyDefault = dummyLanguage.getDefaultVersion();
|
||||
dummyThrows = dummyLanguage.getVersion("1.9-throws");
|
||||
|
||||
processor = new SourceCodeProcessor(new PMDConfiguration());
|
||||
sourceCode = new StringReader("test");
|
||||
Rule rule = new RuleThatThrows();
|
||||
rulesets = Arrays.asList(RulesetsFactoryUtils.defaultFactory().createSingleRuleRuleSet(rule));
|
||||
|
||||
ctx = new RuleContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inErrorRecoveryModeErrorsShouldBeLoggedByParser() {
|
||||
System.setProperty(SystemProps.PMD_ERROR_RECOVERY, "");
|
||||
ctx.setLanguageVersion(dummyThrows);
|
||||
|
||||
Assert.assertThrows(PMDException.class, () -> {
|
||||
processor.processSourceCode(sourceCode, new RuleSets(rulesets), ctx);
|
||||
});
|
||||
// the error is actually logged by PmdRunnable
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inErrorRecoveryModeErrorsShouldBeLoggedByRule() throws Exception {
|
||||
System.setProperty(SystemProps.PMD_ERROR_RECOVERY, "");
|
||||
ctx.setLanguageVersion(dummyDefault);
|
||||
|
||||
processor.processSourceCode(sourceCode, new RuleSets(rulesets), ctx);
|
||||
Assert.assertEquals(1, ctx.getReport().getProcessingErrors().size());
|
||||
Assert.assertSame(AssertionError.class, ctx.getReport().getProcessingErrors().get(0).getError().getClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withoutErrorRecoveryModeProcessingShouldBeAbortedByParser() {
|
||||
Assert.assertNull(System.getProperty(SystemProps.PMD_ERROR_RECOVERY));
|
||||
ctx.setLanguageVersion(dummyThrows);
|
||||
|
||||
Assert.assertThrows(AssertionError.class, () -> {
|
||||
processor.processSourceCode(sourceCode, new RuleSets(rulesets), ctx);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withoutErrorRecoveryModeProcessingShouldBeAbortedByRule() {
|
||||
Assert.assertNull(System.getProperty(SystemProps.PMD_ERROR_RECOVERY));
|
||||
ctx.setLanguageVersion(dummyDefault);
|
||||
|
||||
Assert.assertThrows(AssertionError.class, () -> {
|
||||
processor.processSourceCode(sourceCode, new RuleSets(rulesets), ctx);
|
||||
});
|
||||
}
|
||||
|
||||
private static class RuleThatThrows extends AbstractRule {
|
||||
|
||||
RuleThatThrows() {
|
||||
Language dummyLanguage = LanguageRegistry.findLanguageByTerseName(DummyLanguageModule.TERSE_NAME);
|
||||
setLanguage(dummyLanguage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(Node target, RuleContext ctx) {
|
||||
throw new AssertionError("test");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ import net.sourceforge.pmd.lang.ast.DummyAstStages;
|
||||
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.ParametricRuleViolation;
|
||||
import net.sourceforge.pmd.lang.rule.impl.DefaultRuleViolationFactory;
|
||||
|
||||
@@ -36,6 +37,7 @@ public class DummyLanguageModule extends BaseLanguageModule {
|
||||
addVersion("1.6", new Handler(), "6");
|
||||
addDefaultVersion("1.7", new Handler(), "7");
|
||||
addVersion("1.8", new Handler(), "8");
|
||||
addVersion("1.9-throws", new HandlerWithParserThatThrows());
|
||||
}
|
||||
|
||||
public static class Handler extends AbstractPmdLanguageVersionHandler {
|
||||
@@ -64,6 +66,18 @@ public class DummyLanguageModule extends BaseLanguageModule {
|
||||
}
|
||||
}
|
||||
|
||||
public static class HandlerWithParserThatThrows extends Handler {
|
||||
@Override
|
||||
public Parser getParser(ParserOptions parserOptions) {
|
||||
return new AbstractParser(parserOptions) {
|
||||
@Override
|
||||
public RootNode parse(String fileName, Reader source) throws ParseException {
|
||||
throw new AssertionError("test error while parsing");
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public static class RuleViolationFactory extends DefaultRuleViolationFactory {
|
||||
|
||||
@Override
|
||||
|
||||
+29
@@ -698,4 +698,33 @@ public class Foo {
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
<test-code>
|
||||
<description>AvoidReassigningLoopVariables detects some harmless reassigning of loop variables in foreach #2595</description>
|
||||
<rule-property name="foreachReassign">firstOnly</rule-property>
|
||||
<expected-problems>1</expected-problems>
|
||||
<expected-linenumbers>6</expected-linenumbers>
|
||||
<code><![CDATA[
|
||||
public class Foo {
|
||||
void foo(int bar) {
|
||||
String[] strings = getStrings();
|
||||
for (String g : strings) {
|
||||
g = g.substring(0,g.lastIndexOf(":"));
|
||||
g = g + ": 1;"; // here
|
||||
FileUtil.writeLineToFile(w, g);
|
||||
}
|
||||
for (String item : strings) {
|
||||
item = item.trim();
|
||||
httpMethods = httpMethods | HttpMethods.getMethod(item);
|
||||
}
|
||||
for (String message : strings) {
|
||||
message = OutputFormatter.escape(message);
|
||||
lines.add(String.format(large ? " %s " : " %s ", message));
|
||||
len = Math.max(length(message) + (large ? 4 : 2), len);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
</test-data>
|
||||
Reference in new issue
Block a user