Skip to content

Commit 98b2d8f

Browse files
SONARPY-976 Rule S6396: Superfluous curly brace quantifiers should be… (#1102)
1 parent 9746835 commit 98b2d8f

File tree

8 files changed

+144
-1
lines changed

8 files changed

+144
-1
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
'project:tensorflow/tools/api/tests/api_compatibility_test.py':[
3+
131,
4+
147,
5+
],
6+
}

python-checks/src/main/java/org/sonar/python/checks/CheckList.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
import org.sonar.python.checks.regex.StringReplaceCheck;
6767
import org.sonar.python.checks.regex.UnquantifiedNonCapturingGroupCheck;
6868
import org.sonar.python.checks.regex.VerboseRegexCheck;
69+
import org.sonar.python.checks.regex.SuperfluousCurlyBraceCheck;
6970

7071
public final class CheckList {
7172

@@ -235,6 +236,7 @@ public static Iterable<Class> getChecks() {
235236
StringLiteralDuplicationCheck.class,
236237
StringReplaceCheck.class,
237238
StrongCryptographicKeysCheck.class,
239+
SuperfluousCurlyBraceCheck.class,
238240
TempFileCreationCheck.class,
239241
ToDoCommentCheck.class,
240242
TooManyLinesInFileCheck.class,
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* SonarQube Python Plugin
3+
* Copyright (C) 2011-2022 SonarSource SA
4+
* mailto:info AT sonarsource DOT com
5+
*
6+
* This program is free software; you can redistribute it and/or
7+
* modify it under the terms of the GNU Lesser General Public
8+
* License as published by the Free Software Foundation; either
9+
* version 3 of the License, or (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14+
* Lesser General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU Lesser General Public License
17+
* along with this program; if not, write to the Free Software Foundation,
18+
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19+
*/
20+
package org.sonar.python.checks.regex;
21+
22+
import org.sonar.check.Rule;
23+
import org.sonar.plugins.python.api.tree.CallExpression;
24+
import org.sonarsource.analyzer.commons.regex.RegexParseResult;
25+
import org.sonarsource.analyzer.commons.regex.finders.SuperfluousCurlyBraceFinder;
26+
27+
@Rule(key = "S6396")
28+
public class SuperfluousCurlyBraceCheck extends AbstractRegexCheck {
29+
30+
@Override
31+
public void checkRegex(RegexParseResult regexParseResult, CallExpression regexFunctionCall) {
32+
new SuperfluousCurlyBraceFinder(this::addIssue).visit(regexParseResult);
33+
}
34+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<p>Curly brace quantifiers in regular expressions can be used to have a more fine-grained control over how many times the character or the
2+
sub-expression preceeding them should occur. They can be used to match an expression exactly n times with <code>{n}</code>, between n and m times with
3+
<code>{n,m}</code>, or at least n times with <code>{n,}</code>. In some cases, using such a quantifier is superfluous for the semantic of the regular
4+
expression, and it can be removed to improve readability. This rule raises an issue when one of the following quantifiers is encountered:</p>
5+
<ul>
6+
<li> <code>{1,1}</code> or <code>{1}</code>: they match the expression exactly once. The same behavior can be achieved without the quantifier. </li>
7+
<li> <code>{0,0}</code> or <code>{0}</code>: they match the expression zero times. The same behavior can be achieved by removing the expression.
8+
</li>
9+
</ul>
10+
<h2>Noncompliant Code Example</h2>
11+
<pre>
12+
r"ab{1,1}c"
13+
r"ab{1}c"
14+
r"ab{0,0}c"
15+
r"ab{0}c"
16+
</pre>
17+
<h2>Compliant Solution</h2>
18+
<pre>
19+
r"abc"
20+
r"ac"
21+
</pre>
22+
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"title": "Superfluous curly brace quantifiers should be avoided",
3+
"type": "CODE_SMELL",
4+
"status": "ready",
5+
"remediation": {
6+
"func": "Constant\/Issue",
7+
"constantCost": "5min"
8+
},
9+
"tags": [
10+
"regex"
11+
],
12+
"defaultSeverity": "Major",
13+
"ruleSpecification": "RSPEC-6396",
14+
"sqKey": "S6396",
15+
"scope": "All",
16+
"quickfix": "unknown"
17+
}

python-checks/src/main/resources/org/sonar/l10n/py/rules/python/Sonar_way_profile.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@
154154
"S6323",
155155
"S6331",
156156
"S6035",
157-
"S6395"
157+
"S6395",
158+
"S6396"
158159
]
159160
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* SonarQube Python Plugin
3+
* Copyright (C) 2011-2022 SonarSource SA
4+
* mailto:info AT sonarsource DOT com
5+
*
6+
* This program is free software; you can redistribute it and/or
7+
* modify it under the terms of the GNU Lesser General Public
8+
* License as published by the Free Software Foundation; either
9+
* version 3 of the License, or (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14+
* Lesser General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU Lesser General Public License
17+
* along with this program; if not, write to the Free Software Foundation,
18+
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19+
*/
20+
package org.sonar.python.checks.regex;
21+
22+
import org.junit.Test;
23+
import org.sonar.python.checks.utils.PythonCheckVerifier;
24+
25+
public class SuperfluousCurlyBraceCheckTest {
26+
27+
@Test
28+
public void test() {
29+
PythonCheckVerifier.verify("src/test/resources/checks/regex/superfluousCurlyBraceCheck.py", new SuperfluousCurlyBraceCheck());
30+
}
31+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import re
2+
3+
4+
def non_compliant():
5+
input = "Bob is a Bird... Bob is a Plane... Bob is Superman!"
6+
7+
changed = re.match(r"(abc){1}", input) # Noncompliant {{Remove this unnecessary quantifier.}}
8+
# ^^^
9+
changed = re.match(r"(abc){1,1}", input) # Noncompliant {{Remove this unnecessary quantifier.}}
10+
# ^^^^^
11+
changed = re.match(r"(abc){0}", input) # Noncompliant {{Remove this unnecessarily quantified expression.}}
12+
# ^^^^^^^^
13+
changed = re.match(r"(abc){0,0}", input) # Noncompliant {{Remove this unnecessarily quantified expression.}}
14+
# ^^^^^^^^^^
15+
16+
17+
def compliant():
18+
input = "Bob is a Bird... Bob is a Plane... Bob is Superman! abcabcabcabcabc"
19+
changed = re.match(r"(abc){0,}", input)
20+
changed = re.match(r"(abc){1,}", input)
21+
changed = re.match(r"(abc){1,2,3}", input)
22+
23+
changed = re.match(r"(abc){0,}", input)
24+
changed = re.match(r"(abc){2}", input)
25+
changed = re.match(r"(abc){1,2}", input)
26+
changed = re.match(r"(abc){0,1}", input)
27+
28+
29+
def coverage(input):
30+
re.match(r"Bob is", input)

0 commit comments

Comments
 (0)