diff --git a/pmd/src/main/java/net/sourceforge/pmd/lang/ecmascript/Ecmascript3Parser.java b/pmd/src/main/java/net/sourceforge/pmd/lang/ecmascript/Ecmascript3Parser.java index c6b6b3afe5..24962ddabb 100644 --- a/pmd/src/main/java/net/sourceforge/pmd/lang/ecmascript/Ecmascript3Parser.java +++ b/pmd/src/main/java/net/sourceforge/pmd/lang/ecmascript/Ecmascript3Parser.java @@ -4,7 +4,6 @@ package net.sourceforge.pmd.lang.ecmascript; import java.io.Reader; -import java.util.HashMap; import java.util.Map; import net.sourceforge.pmd.lang.AbstractParser; @@ -17,9 +16,11 @@ import net.sourceforge.pmd.lang.ast.ParseException; * Adapter for the EcmascriptParser. */ public class Ecmascript3Parser extends AbstractParser { + private net.sourceforge.pmd.lang.ecmascript.ast.EcmascriptParser ecmascriptParser; public Ecmascript3Parser(ParserOptions parserOptions) { super(parserOptions); + ecmascriptParser = new net.sourceforge.pmd.lang.ecmascript.ast.EcmascriptParser((EcmascriptParserOptions)parserOptions); } @Override @@ -32,10 +33,10 @@ public class Ecmascript3Parser extends AbstractParser { } public Node parse(String fileName, Reader source) throws ParseException { - return new net.sourceforge.pmd.lang.ecmascript.ast.EcmascriptParser((EcmascriptParserOptions)parserOptions).parse(source); + return ecmascriptParser.parse(source); } public Map getSuppressMap() { - return new HashMap(); // FIXME + return ecmascriptParser.getSuppressMap(); } } diff --git a/pmd/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/EcmascriptParser.java b/pmd/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/EcmascriptParser.java index aedffdd685..2550ffef8e 100644 --- a/pmd/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/EcmascriptParser.java +++ b/pmd/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/EcmascriptParser.java @@ -6,7 +6,9 @@ package net.sourceforge.pmd.lang.ecmascript.ast; import java.io.IOException; import java.io.Reader; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import net.sourceforge.pmd.lang.ast.ParseException; import net.sourceforge.pmd.lang.ecmascript.EcmascriptParserOptions; @@ -15,14 +17,21 @@ import org.apache.commons.io.IOUtils; import org.mozilla.javascript.CompilerEnvirons; import org.mozilla.javascript.Parser; import org.mozilla.javascript.ast.AstRoot; +import org.mozilla.javascript.ast.Comment; import org.mozilla.javascript.ast.ErrorCollector; import org.mozilla.javascript.ast.ParseProblem; public class EcmascriptParser { protected final EcmascriptParserOptions parserOptions; + private Map suppressMap; + private String suppressMarker = "NOPMD"; // that's the default value + public EcmascriptParser(EcmascriptParserOptions parserOptions) { - this.parserOptions = parserOptions; + this.parserOptions = parserOptions; + if (parserOptions.getSuppressMarker() != null) { + suppressMarker = parserOptions.getSuppressMarker(); + } } protected AstRoot parseEcmascript(final String sourceCode, final List parseProblems) throws ParseException { @@ -51,9 +60,26 @@ public class EcmascriptParser { final String sourceCode = IOUtils.toString(reader); final AstRoot astRoot = parseEcmascript(sourceCode, parseProblems); final EcmascriptTreeBuilder treeBuilder = new EcmascriptTreeBuilder(sourceCode, parseProblems); - return treeBuilder.build(astRoot); + EcmascriptNode tree = treeBuilder.build(astRoot); + + suppressMap = new HashMap(); + if (astRoot.getComments() != null) { + for (Comment comment : astRoot.getComments()) { + int nopmd = comment.getValue().indexOf(suppressMarker); + if (nopmd > -1) { + String suppression = comment.getValue().substring(nopmd + suppressMarker.length()); + EcmascriptNode node = treeBuilder.build(comment); + suppressMap.put(node.getBeginLine(), suppression); + } + } + } + return tree; } catch (IOException e) { throw new ParseException(e); } } + + public Map getSuppressMap() { + return suppressMap; + } } diff --git a/pmd/src/site/markdown/changelog.md b/pmd/src/site/markdown/changelog.md index 36d20bfd0c..082aba77ed 100644 --- a/pmd/src/site/markdown/changelog.md +++ b/pmd/src/site/markdown/changelog.md @@ -58,6 +58,7 @@ * Fixed [bug 1141]: ECMAScript: getFinallyBlock() is buggy. * Fixed [bug 1142]: ECMAScript: getCatchClause() is buggy. * Fixed [bug 1144]: CPD encoding argument has no effect +* Fixed [bug 1045]: //NOPMD not working (or not implemented) with ECMAscript * Fixed [bug 1146]: UseArrayListInsteadOfVector false positive when using own Vector class * Fixed [bug 1147]: EmptyMethodInAbstractClassShouldBeAbstract false positives * Fixed [bug 1150]: "EmptyExpression" for valid statements! @@ -85,6 +86,7 @@ [bug 1141]: https://sourceforge.net/p/pmd/bugs/1141 [bug 1142]: https://sourceforge.net/p/pmd/bugs/1142 [bug 1144]: https://sourceforge.net/p/pmd/bugs/1144 +[bug 1045]: https://sourceforge.net/p/pmd/bugs/1045 [bug 1146]: https://sourceforge.net/p/pmd/bugs/1146 [bug 1147]: https://sourceforge.net/p/pmd/bugs/1147 [bug 1150]: https://sourceforge.net/p/pmd/bugs/1150 diff --git a/pmd/src/test/java/net/sourceforge/pmd/ReportTest.java b/pmd/src/test/java/net/sourceforge/pmd/ReportTest.java index bbdd34e5d7..ffba4b74a5 100644 --- a/pmd/src/test/java/net/sourceforge/pmd/ReportTest.java +++ b/pmd/src/test/java/net/sourceforge/pmd/ReportTest.java @@ -13,7 +13,11 @@ import java.util.Iterator; import java.util.Map; import junit.framework.JUnit4TestAdapter; +import net.sourceforge.pmd.lang.Language; import net.sourceforge.pmd.lang.LanguageVersion; +import net.sourceforge.pmd.lang.ecmascript.ast.ASTFunctionNode; +import net.sourceforge.pmd.lang.ecmascript.rule.AbstractEcmascriptRule; +import net.sourceforge.pmd.lang.ecmascript.rule.EcmascriptRuleViolationFactory; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; import net.sourceforge.pmd.lang.java.ast.DummyJavaNode; import net.sourceforge.pmd.lang.java.ast.JavaNode; @@ -144,6 +148,23 @@ public class ReportTest extends RuleTst implements ReportListener { assertEquals(1, rpt.getSuppressedRuleViolations().size()); } + @Test + public void testExclusionsInReportWithNOPMDEcmascript() throws Exception { + Report rpt = new Report(); + Rule rule = new AbstractEcmascriptRule() { + @Override + public Object visit(ASTFunctionNode node, Object data) { + EcmascriptRuleViolationFactory.INSTANCE.addViolation((RuleContext)data, this, node, "Test", null); + return super.visit(node, data); + } + }; + String code = "function(x) // NOPMD test suppress\n" + + "{ x = 1; }"; + runTestFromString(code, rule, rpt, Language.ECMASCRIPT.getDefaultVersion()); + assertTrue(rpt.isEmpty()); + assertEquals(1, rpt.getSuppressedRuleViolations().size()); + } + private static final String TEST1 = "public class Foo {}" + PMD.EOL; diff --git a/pmd/src/test/java/net/sourceforge/pmd/lang/ecmascript/ast/EcmascriptParserTest.java b/pmd/src/test/java/net/sourceforge/pmd/lang/ecmascript/ast/EcmascriptParserTest.java index b670dab93b..69a5c0519a 100644 --- a/pmd/src/test/java/net/sourceforge/pmd/lang/ecmascript/ast/EcmascriptParserTest.java +++ b/pmd/src/test/java/net/sourceforge/pmd/lang/ecmascript/ast/EcmascriptParserTest.java @@ -7,6 +7,8 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import java.io.Reader; +import java.io.StringReader; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -14,6 +16,8 @@ import java.util.List; import net.sourceforge.pmd.PMD; import net.sourceforge.pmd.RuleContext; import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.ecmascript.Ecmascript3Parser; +import net.sourceforge.pmd.lang.ecmascript.EcmascriptParserOptions; import net.sourceforge.pmd.lang.ecmascript.rule.AbstractEcmascriptRule; import org.junit.Test; @@ -145,4 +149,30 @@ public class EcmascriptParserTest extends EcmascriptParserTestBase { assertTrue(block.jjtGetChild(0) instanceof ASTExpressionStatement); assertTrue(block.jjtGetChild(0).jjtGetChild(0) instanceof ASTAssignment); } + + /** + * https://sourceforge.net/p/pmd/bugs/1045/ + * #1045 //NOPMD not working (or not implemented) with ECMAscript + */ + @Test + public void testSuppresionComment() { + Ecmascript3Parser parser = new Ecmascript3Parser(new EcmascriptParserOptions()); + Reader sourceCode = new StringReader("function(x) {\n" + + "x = x; //NOPMD I know what I'm doing\n" + + "}\n"); + parser.parse("foo", sourceCode); + assertEquals(" I know what I'm doing", parser.getSuppressMap().get(2)); + assertEquals(1, parser.getSuppressMap().size()); + + EcmascriptParserOptions parserOptions = new EcmascriptParserOptions(); + parserOptions.setSuppressMarker("FOOOO"); + parser = new Ecmascript3Parser(parserOptions); + sourceCode = new StringReader("function(x) {\n" + + "y = y; //NOPMD xyz\n" + + "x = x; //FOOOO I know what I'm doing\n" + + "}\n"); + parser.parse("foo", sourceCode); + assertEquals(" I know what I'm doing", parser.getSuppressMap().get(3)); + assertEquals(1, parser.getSuppressMap().size()); + } }