Add contexted stackoverflow error

This commit is contained in:
Clément Fournier committed 2021-05-15 21:18:23 +02:00
1 parent 399106116f
commit dcf4234508
5 files changed
+124 -32

No files matched your search

@@ -142,6 +142,10 @@ public final class AssertionUtil {
return ContextedAssertionError.wrap(e);
}
public static @NonNull ContextedStackOverflowError contexted(StackOverflowError e) {
return ContextedStackOverflowError.wrap(e);
}
public static @NonNull ContextedRuntimeException contexted(RuntimeException e) {
return e instanceof ContextedRuntimeException ? (ContextedRuntimeException) e
: new ContextedRuntimeException(e);
@@ -0,0 +1,73 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.internal.util;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang3.exception.DefaultExceptionContext;
import org.apache.commons.lang3.exception.ExceptionContext;
import org.apache.commons.lang3.tuple.Pair;
/**
* A {@link StackOverflowError} with nice messages.
*/
public final class ContextedStackOverflowError extends StackOverflowError implements ExceptionContext {
private final ExceptionContext exceptionContext = new DefaultExceptionContext();
private ContextedStackOverflowError(StackOverflowError e) {
super(e.getMessage());
setStackTrace(e.getStackTrace()); // pretend we're a regular assertion error
}
public static ContextedStackOverflowError wrap(StackOverflowError e) {
return e instanceof ContextedStackOverflowError ? (ContextedStackOverflowError) e
: new ContextedStackOverflowError(e);
}
@Override
public String getMessage() {
return getFormattedExceptionMessage(super.getMessage());
}
@Override
public ContextedStackOverflowError addContextValue(String label, Object value) {
exceptionContext.addContextValue(label, value);
return this;
}
@Override
public ContextedStackOverflowError setContextValue(String label, Object value) {
exceptionContext.addContextValue(label, value);
return this;
}
@Override
public List<Object> getContextValues(String label) {
return exceptionContext.getContextValues(label);
}
@Override
public Object getFirstContextValue(String label) {
return exceptionContext.getFirstContextValue(label);
}
@Override
public Set<String> getContextLabels() {
return exceptionContext.getContextLabels();
}
@Override
public List<Pair<String, Object>> getContextEntries() {
return exceptionContext.getContextEntries();
}
@Override
public String getFormattedExceptionMessage(String baseMessage) {
return exceptionContext.getFormattedExceptionMessage(baseMessage);
}
}
@@ -9,6 +9,8 @@ import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.lang3.exception.ExceptionContext;
import net.sourceforge.pmd.Report.ProcessingError;
import net.sourceforge.pmd.Rule;
import net.sourceforge.pmd.RuleContext;
@@ -63,25 +65,25 @@ public class RuleApplicator {
rule.apply(node, ctx);
rcto.close(1);
} catch (RuntimeException e) {
reportOrRethrow(ctx, rule, node, e, ctx.isIgnoreExceptions());
} catch (AssertionError | StackOverflowError e) {
reportOrRethrow(ctx, rule, node, e, SystemProps.isErrorRecoveryMode());
reportOrRethrow(ctx, rule, node, AssertionUtil.contexted(e), ctx.isIgnoreExceptions());
} catch (StackOverflowError e) {
reportOrRethrow(ctx, rule, node, AssertionUtil.contexted(e), SystemProps.isErrorRecoveryMode());
} catch (AssertionError e) {
reportOrRethrow(ctx, rule, node, AssertionUtil.contexted(e), SystemProps.isErrorRecoveryMode());
}
}
}
}
private <E extends Throwable> void reportOrRethrow(RuleContext ctx, Rule rule, Node node, E e, boolean reportAndDontThrow) throws E {
if (e instanceof ExceptionContext) {
((ExceptionContext) e).addContextValue("Rule applied on node", node);
}
if (reportAndDontThrow) {
reportException(ctx, rule, node, e);
} else {
if (e instanceof RuntimeException) {
throw AssertionUtil.contexted((RuntimeException) e).addContextValue("Rule applied on node", node);
} else if (e instanceof AssertionError) {
throw AssertionUtil.contexted((AssertionError) e).addContextValue("Rule applied on node", node);
} else {
throw e;
}
throw e;
}
}
@@ -6,6 +6,11 @@ package net.sourceforge.pmd;
import static net.sourceforge.pmd.util.CollectionUtil.listOf;
import static net.sourceforge.pmd.util.CollectionUtil.setOf;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasSize;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -492,7 +497,7 @@ public class RuleSetTest {
.addRule(new MockRule() {
@Override
public void apply(Node nodes, RuleContext ctx) {
throw new RuntimeException("Test exception while applying rule");
throw new IllegalStateException("Test exception while applying rule");
}
})
.build();
@@ -504,10 +509,11 @@ public class RuleSetTest {
ruleset.apply(makeCompilationUnits(), context);
List<ProcessingError> errors = context.getReport().getProcessingErrors();
assertTrue("Report should have processing errors", !errors.isEmpty());
assertEquals("Errors expected", 1, errors.size());
assertEquals("Wrong error message", "RuntimeException: Test exception while applying rule", errors.get(0).getMsg());
assertTrue("Should be a RuntimeException", errors.get(0).getError() instanceof RuntimeException);
assertThat(errors, hasSize(1));
ProcessingError error = errors.get(0);
assertThat(error.getMsg(), containsString("java.lang.IllegalStateException: Test exception while applying rule\n"));
assertThat(error.getMsg(), containsString("Rule applied on node=Foo"));
assertThat(error.getError().getCause(), instanceOf(IllegalStateException.class));
}
@Test(expected = RuntimeException.class)
@@ -533,7 +539,7 @@ public class RuleSetTest {
RuleSet ruleset = createRuleSetBuilder("ruleExceptionShouldBeReported").addRule(new MockRule() {
@Override
public void apply(Node target, RuleContext ctx) {
throw new RuntimeException("Test exception while applying rule");
throw new IllegalStateException("Test exception while applying rule");
}
}).addRule(new MockRule() {
@Override
@@ -549,16 +555,14 @@ public class RuleSetTest {
ruleset.apply(makeCompilationUnits(), context);
List<ProcessingError> errors = context.getReport().getProcessingErrors();
assertFalse("Report should have processing errors", errors.isEmpty());
assertEquals("Errors expected", 1, errors.size());
ProcessingError processingError = errors.get(0);
assertEquals("Wrong error message", "RuntimeException: Test exception while applying rule", processingError.getMsg());
assertTrue("Should be a RuntimeException", processingError.getError() instanceof RuntimeException);
assertEquals("Wrong filename in processing error",
"net.sourceforge.pmd.RuleSetTest/ruleExceptionShouldBeReported.java",
FilenameUtils.normalize(processingError.getFile(), true));
assertThat(errors, hasSize(1));
ProcessingError error = errors.get(0);
assertThat(error.getMsg(), containsString("java.lang.IllegalStateException: Test exception while applying rule\n"));
assertThat(error.getMsg(), containsString("Rule applied on node=Foo"));
assertThat(error.getError().getCause(), instanceOf(IllegalStateException.class));
assertThat(FilenameUtils.normalize(error.getFile(), true), equalTo("net.sourceforge.pmd.RuleSetTest/ruleExceptionShouldBeReported.java"));
assertEquals("There should be a violation", 1, context.getReport().getViolations().size());
assertThat(context.getReport().getViolations(), hasSize(1));
}
@Test
@@ -572,7 +576,7 @@ public class RuleSetTest {
@Override
public void apply(Node target, RuleContext ctx) {
throw new RuntimeException("Test exception while applying rule");
throw new UnsupportedOperationException("Test exception while applying rule");
}
}).addRule(new MockRule() {
@@ -595,11 +599,13 @@ public class RuleSetTest {
rulesets.apply(makeCompilationUnits(), context);
List<ProcessingError> errors = context.getReport().getProcessingErrors();
assertEquals("Errors expected", 1, errors.size());
assertEquals("Wrong error message", "RuntimeException: Test exception while applying rule", errors.get(0).getMsg());
assertTrue("Should be a RuntimeException", errors.get(0).getError() instanceof RuntimeException);
assertThat(errors, hasSize(1));
ProcessingError error = errors.get(0);
assertThat(error.getMsg(), containsString("java.lang.UnsupportedOperationException: Test exception while applying rule\n"));
assertThat(error.getMsg(), containsString("Rule applied on node=Foo"));
assertThat(error.getError().getCause(), instanceOf(UnsupportedOperationException.class));
assertEquals("There should be a violation", 1, context.getReport().getViolations().size());
assertThat(context.getReport().getViolations(), hasSize(1));
}
@@ -4,6 +4,10 @@
package net.sourceforge.pmd;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasSize;
import java.io.StringReader;
import java.util.Arrays;
import java.util.List;
@@ -14,7 +18,9 @@ import org.junit.Test;
import org.junit.contrib.java.lang.system.RestoreSystemProperties;
import org.junit.rules.TestRule;
import net.sourceforge.pmd.Report.ProcessingError;
import net.sourceforge.pmd.internal.SystemProps;
import net.sourceforge.pmd.internal.util.ContextedAssertionError;
import net.sourceforge.pmd.lang.DummyLanguageModule;
import net.sourceforge.pmd.lang.Language;
import net.sourceforge.pmd.lang.LanguageRegistry;
@@ -65,8 +71,9 @@ public class SourceCodeProcessorTest {
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());
List<ProcessingError> errors = ctx.getReport().getProcessingErrors();
assertThat(errors, hasSize(1));
assertThat(errors.get(0).getError(), instanceOf(ContextedAssertionError.class));
}
@Test