diff --git a/libs/natlint/src/main/java/org/amshove/natlint/analyzers/UnnecessaryIgnoreAnalyzer.java b/libs/natlint/src/main/java/org/amshove/natlint/analyzers/UnnecessaryIgnoreAnalyzer.java new file mode 100644 index 000000000..05837bd3e --- /dev/null +++ b/libs/natlint/src/main/java/org/amshove/natlint/analyzers/UnnecessaryIgnoreAnalyzer.java @@ -0,0 +1,48 @@ +package org.amshove.natlint.analyzers; + +import org.amshove.natlint.api.AbstractAnalyzer; +import org.amshove.natlint.api.DiagnosticDescription; +import org.amshove.natlint.api.IAnalyzeContext; +import org.amshove.natlint.api.ILinterContext; +import org.amshove.natparse.DiagnosticSeverity; +import org.amshove.natparse.NodeUtil; +import org.amshove.natparse.ReadOnlyList; +import org.amshove.natparse.natural.IIgnoreNode; +import org.amshove.natparse.natural.IStatementListNode; +import org.amshove.natparse.natural.ISyntaxNode; + +public class UnnecessaryIgnoreAnalyzer extends AbstractAnalyzer +{ + public static final DiagnosticDescription UNNECESSARY_IGNORE = DiagnosticDescription.create( + "NL025", + "IGNORE is unnecessary", + DiagnosticSeverity.INFO + ); + + @Override + public ReadOnlyList getDiagnosticDescriptions() + { + return ReadOnlyList.of(UNNECESSARY_IGNORE); + } + + @Override + public void initialize(ILinterContext context) + { + context.registerNodeAnalyzer(IIgnoreNode.class, this::analyzeIgnore); + } + + private void analyzeIgnore(ISyntaxNode node, IAnalyzeContext context) + { + var ignore = (IIgnoreNode) node; + + if (!(NodeUtil.findFirstParentOfType(ignore, IStatementListNode.class)instanceof IStatementListNode parent)) + { + return; + } + + if (parent.statements().size() > 1) + { + context.report(UNNECESSARY_IGNORE.createDiagnostic(ignore)); + } + } +} diff --git a/libs/natlint/src/test/java/org/amshove/natlint/analyzers/UnnecessaryIgnoreAnalyzerShould.java b/libs/natlint/src/test/java/org/amshove/natlint/analyzers/UnnecessaryIgnoreAnalyzerShould.java new file mode 100644 index 000000000..97376d949 --- /dev/null +++ b/libs/natlint/src/test/java/org/amshove/natlint/analyzers/UnnecessaryIgnoreAnalyzerShould.java @@ -0,0 +1,83 @@ +package org.amshove.natlint.analyzers; + +import org.amshove.natlint.linter.AbstractAnalyzerTest; +import org.junit.jupiter.api.Test; + +class UnnecessaryIgnoreAnalyzerShould extends AbstractAnalyzerTest +{ + protected UnnecessaryIgnoreAnalyzerShould() + { + super(new UnnecessaryIgnoreAnalyzer()); + } + + @Test + void reportADiagnosticIfIgnoreIsUnnecessaryInIfs() + { + testDiagnostics( + """ + DEFINE DATA LOCAL + END-DEFINE + IF TRUE + WRITE 'Hi' + IGNORE + END-IF + END + """, + expectDiagnostic(4, UnnecessaryIgnoreAnalyzer.UNNECESSARY_IGNORE) + ); + } + + @Test + void reportNoDiagnosticIfIgnoreIsNeccessaryInIfs() + { + testDiagnostics( + """ + DEFINE DATA LOCAL + END-DEFINE + IF TRUE + IGNORE + END-IF + END + """, + expectNoDiagnosticOfType(UnnecessaryIgnoreAnalyzer.UNNECESSARY_IGNORE) + ); + } + + @Test + void reportADiagnosticIfIgnoreIsTheOnlyStatementInAModule() + { + testDiagnostics( + """ + DEFINE DATA LOCAL + END-DEFINE + IGNORE + END + """, + expectDiagnostic(2, UnnecessaryIgnoreAnalyzer.UNNECESSARY_IGNORE) + ); + } + + @Test + void reportNoDiagnosticIfIgnoreIsNeccessaryInDecideBlcosk() + { + testDiagnostics( + """ + DEFINE DATA LOCAL + 1 #VAR (N1) + END-DEFINE + DECIDE ON FIRST VALUE OF #VAR + VALUE 1 + IGNORE + VALUE 2 + IGNORE + NONE VALUE + IGNORE + ANY VALUE + IGNORE + END-DECIDE + END + """, + expectNoDiagnosticOfType(UnnecessaryIgnoreAnalyzer.UNNECESSARY_IGNORE) + ); + } +} diff --git a/tools/ruletranslator/src/main/resources/rules/NL025 b/tools/ruletranslator/src/main/resources/rules/NL025 new file mode 100644 index 000000000..282197329 --- /dev/null +++ b/tools/ruletranslator/src/main/resources/rules/NL025 @@ -0,0 +1,6 @@ +name: IGNORE is unnecessary +priority: MINOR +tags: pitfall,confusing +type: CODE_SMELL +description: +If an ``IGNORE`` is not the only statement in a block, it is unnecessary and can be removed.