[core] Fix NPE in AbstractAnalysisCache in case of processing errors

This commit is contained in:
Andreas Dangel
2024-03-01 14:50:35 +01:00
parent 150c0c88a4
commit 5e277c8211
2 changed files with 36 additions and 1 deletions

View File

@ -215,13 +215,18 @@ abstract class AbstractAnalysisCache implements AnalysisCache {
final FileId fileName = file.getFileId();
return new FileAnalysisListener() {
private boolean failed = false;
@Override
public void onRuleViolation(RuleViolation violation) {
updatedResultsCache.get(fileName).addViolation(violation);
if (!failed) {
updatedResultsCache.get(fileName).addViolation(violation);
}
}
@Override
public void onError(ProcessingError error) {
failed = true;
analysisFailed(file);
}
};

View File

@ -48,6 +48,7 @@ import net.sourceforge.pmd.lang.rule.Rule;
import net.sourceforge.pmd.lang.rule.internal.RuleSets;
import net.sourceforge.pmd.reporting.FileAnalysisListener;
import net.sourceforge.pmd.reporting.InternalApiBridge;
import net.sourceforge.pmd.reporting.Report;
import net.sourceforge.pmd.reporting.RuleViolation;
class FileAnalysisCacheTest {
@ -146,6 +147,35 @@ class FileAnalysisCacheTest {
assertEquals(textLocation.getEndColumn(), cachedViolation.getEndColumn());
}
@Test
void testStorePersistsFilesWithViolationsAndProcessingErrors() throws IOException {
final FileAnalysisCache cache = new FileAnalysisCache(newCacheFile);
cache.checkValidity(mock(RuleSets.class), mock(ClassLoader.class), setOf(sourceFileBackend));
final FileAnalysisListener cacheListener = cache.startFileAnalysis(sourceFile);
cache.isUpToDate(sourceFile);
cacheListener.onError(new Report.ProcessingError(new RuntimeException("some rule failed"), sourceFile.getFileId()));
final RuleViolation rv = mock(RuleViolation.class);
final TextRange2d textLocation = TextRange2d.range2d(1, 2, 3, 4);
when(rv.getLocation()).thenReturn(FileLocation.range(sourceFile.getFileId(), textLocation));
final Rule rule = mock(Rule.class, Mockito.RETURNS_SMART_NULLS);
when(rule.getLanguage()).thenReturn(mock(Language.class));
when(rv.getRule()).thenReturn(rule);
// the next rule wants to report a violation
cacheListener.onRuleViolation(rv);
cache.persist();
final FileAnalysisCache reloadedCache = new FileAnalysisCache(newCacheFile);
reloadedCache.checkValidity(mock(RuleSets.class), mock(ClassLoader.class), setOf(sourceFileBackend));
assertFalse(reloadedCache.isUpToDate(sourceFile),
"Cache believes file is up to date although processing errors happened earlier");
final List<RuleViolation> cachedViolations = reloadedCache.getCachedViolations(sourceFile);
assertTrue(cachedViolations.isEmpty(), "There should be no cached rule violations");
}
@Test
void testDisplayNameIsRespected() throws Exception {