Make semantic errors report processing errors
This commit is contained in:
@ -6,6 +6,7 @@ package net.sourceforge.pmd.lang.ast;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.slf4j.event.Level;
|
||||
|
||||
import net.sourceforge.pmd.util.StringUtil;
|
||||
@ -45,14 +46,17 @@ public interface SemanticErrorReporter {
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if at least one error has been reported.
|
||||
* If {@link #error(Node, String, Object...)} has been called, return
|
||||
* a semantic exception instance with the correct message. If it has been
|
||||
* called more than once, return the first exception, possibly with suppressed
|
||||
* exceptions for subsequent calls to {@link #error(Node, String, Object...)}.
|
||||
*/
|
||||
boolean hasError();
|
||||
@Nullable SemanticException getFirstError();
|
||||
|
||||
static SemanticErrorReporter noop() {
|
||||
return new SemanticErrorReporter() {
|
||||
|
||||
private boolean hasError = false;
|
||||
private SemanticException exception;
|
||||
|
||||
@Override
|
||||
public void warning(Node location, String message, Object... formatArgs) {
|
||||
@ -61,13 +65,18 @@ public interface SemanticErrorReporter {
|
||||
|
||||
@Override
|
||||
public SemanticException error(Node location, String message, Object... formatArgs) {
|
||||
hasError = true;
|
||||
return new SemanticException(MessageFormat.format(message, formatArgs));
|
||||
SemanticException ex = new SemanticException(MessageFormat.format(message, formatArgs));
|
||||
if (this.exception == null) {
|
||||
this.exception = ex;
|
||||
} else {
|
||||
this.exception.addSuppressed(ex);
|
||||
}
|
||||
return ex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasError() {
|
||||
return hasError;
|
||||
public @Nullable SemanticException getFirstError() {
|
||||
return exception;
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -81,6 +90,8 @@ public interface SemanticErrorReporter {
|
||||
return new SemanticErrorReporter() {
|
||||
private boolean hasError = false;
|
||||
|
||||
private SemanticException exception = null;
|
||||
|
||||
private String locPrefix(Node loc) {
|
||||
return "at " + loc.getAstInfo().getFileName() + " :" + loc.getBeginLine() + ":" + loc.getBeginColumn()
|
||||
+ ": ";
|
||||
@ -105,12 +116,18 @@ public interface SemanticErrorReporter {
|
||||
public SemanticException error(Node location, String message, Object... args) {
|
||||
hasError = true;
|
||||
String fullMessage = logMessage(Level.ERROR, location, message, args);
|
||||
return new SemanticException(fullMessage);
|
||||
SemanticException ex = new SemanticException(fullMessage);
|
||||
if (this.exception == null) {
|
||||
this.exception = ex;
|
||||
} else {
|
||||
this.exception.addSuppressed(ex);
|
||||
}
|
||||
return ex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasError() {
|
||||
return hasError;
|
||||
public @Nullable SemanticException getFirstError() {
|
||||
return exception;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ import net.sourceforge.pmd.lang.ast.Parser;
|
||||
import net.sourceforge.pmd.lang.ast.Parser.ParserTask;
|
||||
import net.sourceforge.pmd.lang.ast.RootNode;
|
||||
import net.sourceforge.pmd.lang.ast.SemanticErrorReporter;
|
||||
import net.sourceforge.pmd.lang.ast.SemanticException;
|
||||
import net.sourceforge.pmd.reporting.FileAnalysisListener;
|
||||
import net.sourceforge.pmd.reporting.GlobalAnalysisListener;
|
||||
import net.sourceforge.pmd.util.datasource.DataSource;
|
||||
@ -148,9 +149,10 @@ abstract class PmdRunnable implements Runnable {
|
||||
|
||||
RootNode rootNode = parse(parser, task);
|
||||
|
||||
if (reporter.hasError()) {
|
||||
configuration.getReporter().info("Errors occurred in file, skipping rule analysis: {0}", filename);
|
||||
return;
|
||||
SemanticException semanticError = reporter.getFirstError();
|
||||
if (semanticError != null) {
|
||||
// cause a processing error to be reported and rule analysis to be skipped
|
||||
throw semanticError;
|
||||
}
|
||||
|
||||
ruleSets.apply(rootNode, listener);
|
||||
|
@ -4,8 +4,8 @@
|
||||
|
||||
package net.sourceforge.pmd.lang.ast;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.mockito.Mockito.contains;
|
||||
import static org.mockito.Mockito.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
@ -48,7 +48,7 @@ public class SemanticErrorReporterTest {
|
||||
SemanticErrorReporter reporter = SemanticErrorReporter.reportToLogger(mockReporter);
|
||||
RootNode node = parseMockNode(reporter);
|
||||
|
||||
assertFalse(reporter.hasError());
|
||||
assertNull(reporter.getFirstError());
|
||||
|
||||
String message = "an error occurred";
|
||||
reporter.error(node, message);
|
||||
@ -56,7 +56,7 @@ public class SemanticErrorReporterTest {
|
||||
verify(mockReporter).log(eq(Level.ERROR), contains(message));
|
||||
verifyNoMoreInteractions(mockLogger);
|
||||
|
||||
assertTrue(reporter.hasError());
|
||||
assertNotNull(reporter.getFirstError());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -132,8 +132,11 @@ public class PmdRunnableTest {
|
||||
|
||||
pmdRunnable.run();
|
||||
|
||||
verify(reporter).log(eq(Level.INFO), contains("skipping rule analysis"));
|
||||
verify(reporter, times(1)).log(eq(Level.ERROR), eq("at test.dummy :1:1: " + TEST_MESSAGE_SEMANTIC_ERROR));
|
||||
verify(rule, never()).apply(Mockito.any(), Mockito.any());
|
||||
|
||||
reportBuilder.close();
|
||||
Assert.assertEquals(1, reportBuilder.getResult().getProcessingErrors().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -144,6 +147,9 @@ public class PmdRunnableTest {
|
||||
|
||||
verify(reporter, times(1)).log(eq(Level.ERROR), contains(TEST_MESSAGE_SEMANTIC_ERROR));
|
||||
verify(rule, never()).apply(Mockito.any(), Mockito.any());
|
||||
|
||||
reportBuilder.close();
|
||||
Assert.assertEquals(1, reportBuilder.getResult().getProcessingErrors().size());
|
||||
}
|
||||
|
||||
public static void registerCustomVersions(BiConsumer<String, Handler> addVersion) {
|
||||
|
@ -15,6 +15,7 @@ import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -144,8 +145,8 @@ public class JavaParsingHelper extends BaseParsingHelper<JavaParsingHelper, ASTC
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasError() {
|
||||
return baseLogger.hasError();
|
||||
public @Nullable SemanticException getFirstError() {
|
||||
return baseLogger.getFirstError();
|
||||
}
|
||||
}
|
||||
|
||||
@ -181,8 +182,8 @@ public class JavaParsingHelper extends BaseParsingHelper<JavaParsingHelper, ASTC
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasError() {
|
||||
return false;
|
||||
public @Nullable SemanticException getFirstError() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user