Skip to content

Commit

Permalink
Merge pull request #341 from guwirth/enhancement/line_regex
Browse files Browse the repository at this point in the history
Line RegEx rule
  • Loading branch information
wenns committed Dec 30, 2014
2 parents 41dbd96 + f30f0e1 commit 7f5eb9e
Show file tree
Hide file tree
Showing 7 changed files with 216 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public static List<Class> getChecks() {
FileHeaderCheck.class,
FileEncodingCheck.class,
FileRegularExpressionCheck.class,
LineRegularExpressionCheck.class,
FixmeTagPresenceCheck.class,
FunctionComplexityCheck.class,
HardcodedAccountCheck.class,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/*
* Sonar C++ Plugin (Community)
* Copyright (C) 2011 Waleri Enns and CONTACT Software GmbH
* dev@sonar.codehaus.org
*
* 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 02
*/
package org.sonar.cxx.checks;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import com.google.common.io.Files;

import org.sonar.check.Cardinality;
import org.sonar.check.Priority;
import org.sonar.check.Rule;
import org.sonar.check.RuleProperty;
import com.sonar.sslr.api.Grammar;
import org.sonar.api.utils.SonarException;
import org.sonar.cxx.visitors.CxxCharsetAwareVisitor;
import org.sonar.squidbridge.checks.SquidCheck;
import org.sonar.api.utils.PathUtils;
import org.sonar.api.utils.WildcardPattern;
import com.sonar.sslr.api.AstNode;

@Rule(
key = "LineRegularExpression",
cardinality = Cardinality.MULTIPLE,
priority = Priority.MAJOR)

public class LineRegularExpressionCheck extends SquidCheck<Grammar> implements CxxCharsetAwareVisitor {

private static final String DEFAULT_MATCH_FILE_PATTERN = "";
private static final String DEFAULT_REGULAR_EXPRESSION = "";
private static final String DEFAULT_MESSAGE = "The regular expression matches this line";

private Charset charset;
private Pattern pattern;

@RuleProperty(
key = "matchFilePattern",
defaultValue = DEFAULT_MATCH_FILE_PATTERN)
public String matchFilePattern = DEFAULT_MATCH_FILE_PATTERN;

@RuleProperty(
key = "regularExpression",
defaultValue = DEFAULT_REGULAR_EXPRESSION)
public String regularExpression = DEFAULT_REGULAR_EXPRESSION;

@RuleProperty(
key = "message",
defaultValue = DEFAULT_MESSAGE)
public String message = DEFAULT_MESSAGE;

@Override
public void init() {
try {
pattern = Pattern.compile(regularExpression);
} catch (PatternSyntaxException e) {
throw new SonarException(e);
}
}

@Override
public void setCharset(Charset charset) {
this.charset = charset;
}

@Override
public void visitFile(AstNode fileNode) {
if (fileNode != null) {
List<String> lines;
try {
lines = Files.readLines(getContext().getFile(), charset);
} catch (IOException e) {
throw new SonarException(e);
}
for (int i = 0; i < lines.size(); ++i) {
Matcher matcher = pattern.matcher(lines.get(i));
if (matcher.find()) {
getContext().createLineViolation(this, message, i + 1);
}
}
}
}

private boolean matchFile() {
if (!matchFilePattern.isEmpty()) {
WildcardPattern filePattern = WildcardPattern.create(matchFilePattern);
String path = PathUtils.sanitize(getContext().getFile().getPath());
return filePattern.match(path);
}
return true;
}

}
4 changes: 4 additions & 0 deletions cxx-checks/src/main/resources/org/sonar/l10n/cxx.properties
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,7 @@ rule.cxx.FileRegularExpression.name=File RegEx rule
rule.cxx.FileRegularExpression.param.matchFilePattern=Ant-style matching patterns for path
rule.cxx.FileRegularExpression.param.message=The violation message
rule.cxx.FileRegularExpression.param.regularExpression=The regular expression
rule.cxx.LineRegularExpression.name=Line RegEx rule
rule.cxx.LineRegularExpression.param.matchFilePattern=Ant-style matching patterns for path
rule.cxx.LineRegularExpression.param.message=The violation message
rule.cxx.LineRegularExpression.param.regularExpression=The regular expression
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<p>
This rule template can be used to create rules which will be triggered when a line matches a given regular expression.
For each match a line violation will be created.
Additional a Ant-style matching pattern for the path can be defined.
</p>

<p>
matchFilePattern allows Ant-style matching patterns for the path. If no matchFilePattern is defined all files are evaluated.
</p>

<p>
Following rules are applied:
</p>
<ul>
<li>? matches single character</li>
<li>* matches zero or more characters</li>
<li>** matches zero or more 'directories'</li>
<li>use always '/' as a directory separator</li>
<li>there must always be a root directory</li>
</ul>

<p>
Some examples of patterns:
</p>
<ul>
<li>/**/*.cpp - matches all .cpp files in all directories (you have to define the root directory '/'), e.g. org/Foo.cpp or org/foo/Bar.cpp or org/foo/bar/Baz.cpp</li>
<li>/**/test/**/Foo.cpp - matches all 'Foo.cpp' files in directories with one 'test' directory in the path, e.g. org/test/Foo.cpp or org/bar/test/bar/Foo.cpp</li>
<li>org/T?st.cpp - matches org/Test.cpp and also org/Tost.cpp</li>
<li>org/*.cpp - matches all .cpp files in the org directory, e.g. org/Foo.cpp or org/Bar.cpp</li>
<li>org/** - matches all files underneath the org directory, e.g. org/Foo.cpp or org/foo/bar.jsp</li>
<li>org/**/Test.cpp - matches all Test.cpp files underneath the org directory, e.g. org/Test.cpp or org/foo/Test.cpp or org/foo/bar/Test.cpp</li>
<li>org/**/*.cpp - matches all .cpp files underneath the org directory, e.g. org/Foo.cpp or org/foo/Bar.cpp or org/foo/bar/Baz.cpp</li>
</ul>

Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ public class CheckListTest {

@Test
public void count() {
assertThat(CheckList.getChecks().size()).isEqualTo(37);
assertThat(CheckList.getChecks().size()).isEqualTo(38);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Sonar C++ Plugin (Community)
* Copyright (C) 2011 Waleri Enns and CONTACT Software GmbH
* dev@sonar.codehaus.org
*
* 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 02
*/
package org.sonar.cxx.checks;

import java.io.File;

import org.junit.Test;
import org.sonar.cxx.CxxAstScanner;
import org.sonar.squidbridge.api.SourceFile;
import org.sonar.squidbridge.checks.CheckMessagesVerifier;

public class LineRegularExpressionCheckTest {

@Test
public void lineRegExWithoutFilePattern() {
LineRegularExpressionCheck check = new LineRegularExpressionCheck();
check.regularExpression = "stdafx\\.h";
check.message = "Found 'stdafx.h' in line!";

SourceFile file = CxxAstScanner.scanSingleFile(new File("src/test/resources/checks/LineRegEx.cc"), check);
CheckMessagesVerifier.verify(file.getCheckMessages())
.next().atLine(2).withMessage(check.message)
.next().atLine(3).withMessage(check.message)
.noMore();
}

@Test
public void lineRegExWithFilePattern() {
LineRegularExpressionCheck check = new LineRegularExpressionCheck();
check.matchFilePattern = "/**/*.cc"; // all files with .cc file extension
check.regularExpression = "#include\\s+\"stdafx\\.h\"";
check.message = "Found '#include \"stdafx.h\"' in line in a .cc file!";

SourceFile file = CxxAstScanner.scanSingleFile(new File("src/test/resources/checks/LineRegEx.cc"), check);
CheckMessagesVerifier.verify(file.getCheckMessages())
.next().atLine(2).withMessage(check.message)
.next().atLine(3).withMessage(check.message)
.noMore();
}

}
6 changes: 6 additions & 0 deletions cxx-checks/src/test/resources/checks/LineRegEx.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Comment
#include "stdafx.h"
#include "stdafx.h"
int i;
void func() {}

0 comments on commit 7f5eb9e

Please sign in to comment.