diff --git a/cxx-checks/src/main/java/org/sonar/cxx/checks/CheckList.java b/cxx-checks/src/main/java/org/sonar/cxx/checks/CheckList.java index ae11567452..62d327588a 100644 --- a/cxx-checks/src/main/java/org/sonar/cxx/checks/CheckList.java +++ b/cxx-checks/src/main/java/org/sonar/cxx/checks/CheckList.java @@ -83,7 +83,9 @@ public static List getChecks() { ClassNameCheck.class, FileNameCheck.class, FunctionNameCheck.class, - MethodNameCheck.class + MethodNameCheck.class, + // XPath + XPathCheck.class )); } diff --git a/cxx-checks/src/main/java/org/sonar/cxx/checks/XPathCheck.java b/cxx-checks/src/main/java/org/sonar/cxx/checks/XPathCheck.java new file mode 100644 index 0000000000..3bc86c64a1 --- /dev/null +++ b/cxx-checks/src/main/java/org/sonar/cxx/checks/XPathCheck.java @@ -0,0 +1,98 @@ +/* + * Sonar C++ Plugin (Community) + * Copyright (C) 2010-2016 SonarOpenCommunity + * http://github.com/SonarOpenCommunity/sonar-cxx + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.cxx.checks; + +import com.sonar.sslr.api.AstNode; +import org.sonar.check.Priority; +import org.sonar.check.Rule; +import org.sonar.check.RuleProperty; +import org.sonar.squidbridge.checks.AbstractXPathCheck; +import com.sonar.sslr.api.Grammar; +import org.sonar.api.utils.PathUtils; +import org.sonar.api.utils.WildcardPattern; +import org.sonar.squidbridge.annotations.NoSqale; +import org.sonar.squidbridge.annotations.RuleTemplate; + +@Rule( + key = "XPath", + name = "XPath rule", + priority = Priority.MAJOR) +@RuleTemplate +@NoSqale +public class XPathCheck extends AbstractXPathCheck { + + private static final String DEFAULT_MATCH_FILE_PATTERN = ""; + private static final boolean DEFAULT_INVERT_FILE_PATTERN = false; + private static final String DEFAULT_XPATH_QUERY = ""; + private static final String DEFAULT_MESSAGE = "The XPath expression matches this piece of code"; + + @RuleProperty( + key = "matchFilePattern", + description = "Ant-style matching patterns for path", + defaultValue = DEFAULT_MATCH_FILE_PATTERN) + public String matchFilePattern = DEFAULT_MATCH_FILE_PATTERN; + + @RuleProperty( + key = "invertFilePattern", + description = "Invert file pattern comparison", + defaultValue = "" + DEFAULT_INVERT_FILE_PATTERN) + public boolean invertFilePattern = DEFAULT_INVERT_FILE_PATTERN; + + @RuleProperty( + key = "xpathQuery", + description = "The XPath query", + type = "TEXT", + defaultValue = DEFAULT_XPATH_QUERY) + public String xpathQuery = DEFAULT_XPATH_QUERY; + + @RuleProperty( + key = "message", + description = "The violation message", + defaultValue = DEFAULT_MESSAGE) + public String message = DEFAULT_MESSAGE; + + @Override + public String getXPathQuery() { + return xpathQuery; + } + + @Override + public String getMessage() { + return message; + } + + @Override + public void visitFile(AstNode fileNode) { + if (fileNode != null) { + if (!matchFilePattern.isEmpty()) { + WildcardPattern pattern = WildcardPattern.create(matchFilePattern); + String path = PathUtils.sanitize(getContext().getFile().getPath()); + if (!compare(invertFilePattern, pattern.match(path))) { + return; + } + } + super.visitFile(fileNode); + } + } + + private boolean compare(boolean invert, boolean condition) { + return invert ? !condition : condition; + } +} diff --git a/cxx-checks/src/test/java/org/sonar/cxx/checks/CheckListTest.java b/cxx-checks/src/test/java/org/sonar/cxx/checks/CheckListTest.java index 893aa11d6f..4452fc28fb 100644 --- a/cxx-checks/src/test/java/org/sonar/cxx/checks/CheckListTest.java +++ b/cxx-checks/src/test/java/org/sonar/cxx/checks/CheckListTest.java @@ -27,6 +27,6 @@ public class CheckListTest { @Test public void count() { - assertThat(CheckList.getChecks().size()).isEqualTo(44); + assertThat(CheckList.getChecks().size()).isEqualTo(45); } } diff --git a/cxx-checks/src/test/java/org/sonar/cxx/checks/XPathCheckTest.java b/cxx-checks/src/test/java/org/sonar/cxx/checks/XPathCheckTest.java new file mode 100644 index 0000000000..5e7ad9e26b --- /dev/null +++ b/cxx-checks/src/test/java/org/sonar/cxx/checks/XPathCheckTest.java @@ -0,0 +1,100 @@ +/* + * Sonar C++ Plugin (Community) + * Copyright (C) 2010-2016 SonarOpenCommunity + * http://github.com/SonarOpenCommunity/sonar-cxx + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.cxx.checks; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; + +import org.junit.Test; +import org.sonar.cxx.CxxAstScanner; +import org.sonar.squidbridge.api.SourceFile; +import org.sonar.squidbridge.checks.CheckMessagesVerifier; + +public class XPathCheckTest { + + @Test + public void xpathWithoutFilePattern() throws UnsupportedEncodingException, IOException { + XPathCheck check = new XPathCheck(); + check.xpathQuery = "//declaration"; + check.message = "Avoid declarations!! "; + + CxxFileTester tester = CxxFileTesterHelper.CreateCxxFileTester("src/test/resources/checks/xpath.cc", "."); + SourceFile file = CxxAstScanner.scanSingleFile(tester.cxxFile, tester.sensorContext, check); + CheckMessagesVerifier.verify(file.getCheckMessages()) + .next().atLine(1).withMessage(check.message) + .noMore(); + } + + @Test + public void xpathWithFilePattern1() throws UnsupportedEncodingException, IOException { + XPathCheck check = new XPathCheck(); + check.matchFilePattern = "/**/*.cc"; // all files with .cc file extension + check.xpathQuery = "//declaration"; + check.message = "Avoid declarations!! "; + + CxxFileTester tester = CxxFileTesterHelper.CreateCxxFileTester("src/test/resources/checks/xpath.cc", "."); + SourceFile file = CxxAstScanner.scanSingleFile(tester.cxxFile, tester.sensorContext, check); + CheckMessagesVerifier.verify(file.getCheckMessages()) + .next().atLine(1).withMessage(check.message) + .noMore(); + } + + @Test + public void xpathWithFilePattern2() throws UnsupportedEncodingException, IOException { + XPathCheck check = new XPathCheck(); + check.matchFilePattern = "/**/test/**/xpath.cc"; // all files with filename xpath.cc in a subdirectory with name test + check.xpathQuery = "//declaration"; + check.message = "Avoid declarations!! "; + + CxxFileTester tester = CxxFileTesterHelper.CreateCxxFileTester("src/test/resources/checks/xpath.cc", "."); + SourceFile file = CxxAstScanner.scanSingleFile(tester.cxxFile, tester.sensorContext, check); + CheckMessagesVerifier.verify(file.getCheckMessages()) + .next().atLine(1).withMessage(check.message) + .noMore(); + } + + @Test + public void xpathWithFilePattern3() throws UnsupportedEncodingException, IOException { + XPathCheck check = new XPathCheck(); + check.matchFilePattern = "/**/*.xxx"; // all files with .xxx file extension + check.xpathQuery = "//declaration"; + check.message = "Avoid declarations!! "; + + CxxFileTester tester = CxxFileTesterHelper.CreateCxxFileTester("src/test/resources/checks/xpath.cc", "."); + SourceFile file = CxxAstScanner.scanSingleFile(tester.cxxFile, tester.sensorContext, check); + CheckMessagesVerifier.verify(file.getCheckMessages()) + .noMore(); + } + + @Test + public void xpathWithFilePatternInvert() throws UnsupportedEncodingException, IOException { + XPathCheck check = new XPathCheck(); + check.matchFilePattern = "/**/*.xxx"; // all files with not .xxx file extension + check.invertFilePattern = true; + check.xpathQuery = "//declaration"; + check.message = "Avoid declarations!! "; + + CxxFileTester tester = CxxFileTesterHelper.CreateCxxFileTester("src/test/resources/checks/xpath.cc", "."); + SourceFile file = CxxAstScanner.scanSingleFile(tester.cxxFile, tester.sensorContext, check); + CheckMessagesVerifier.verify(file.getCheckMessages()) + .next().atLine(1).withMessage(check.message) + .noMore(); + } +} diff --git a/pom.xml b/pom.xml index 01df8b0b87..2aa13345a0 100644 --- a/pom.xml +++ b/pom.xml @@ -226,10 +226,6 @@ org.codehaus.sonar.sslr sslr-core - - org.codehaus.sonar.sslr - sslr-xpath - org.codehaus.sonar sonar-plugin-api diff --git a/sonar-cxx-plugin/src/test/java/org/sonar/plugins/cxx/CxxRuleRepositoryTest.java b/sonar-cxx-plugin/src/test/java/org/sonar/plugins/cxx/CxxRuleRepositoryTest.java index b5b8ee9507..447aaefc14 100644 --- a/sonar-cxx-plugin/src/test/java/org/sonar/plugins/cxx/CxxRuleRepositoryTest.java +++ b/sonar-cxx-plugin/src/test/java/org/sonar/plugins/cxx/CxxRuleRepositoryTest.java @@ -34,6 +34,6 @@ public void rulesTest() { new CxxRuleRepository().define(context); assertThat(context.repositories()).hasSize(1); - assertThat(context.repository(CheckList.REPOSITORY_KEY).rules()).hasSize(44); + assertThat(context.repository(CheckList.REPOSITORY_KEY).rules()).hasSize(45); } }