From 5061b57de5bf83d4d4b67146f0ddcebe9d37be0e Mon Sep 17 00:00:00 2001 From: Guillaume Dequenne Date: Mon, 18 May 2020 14:47:24 +0200 Subject: [PATCH 1/2] SONARPY-664 Rule S5781: Expressions creating sets should not have duplicate values --- .../checks/AbstractDuplicateKeyCheck.java | 108 ++++++++++++++++++ .../org/sonar/python/checks/CheckList.java | 1 + .../checks/DictionaryDuplicateKeyCheck.java | 83 +------------- .../python/checks/SetDuplicateKeyCheck.java | 68 +++++++++++ .../org/sonar/l10n/py/rules/python/S5781.html | 22 ++++ .../org/sonar/l10n/py/rules/python/S5781.json | 12 ++ .../py/rules/python/Sonar_way_profile.json | 1 + .../checks/SetDuplicateKeyCheckTest.java | 31 +++++ .../test/resources/checks/setDuplicateKey.py | 96 ++++++++++++++++ 9 files changed, 340 insertions(+), 82 deletions(-) create mode 100644 python-checks/src/main/java/org/sonar/python/checks/AbstractDuplicateKeyCheck.java create mode 100644 python-checks/src/main/java/org/sonar/python/checks/SetDuplicateKeyCheck.java create mode 100644 python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S5781.html create mode 100644 python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S5781.json create mode 100644 python-checks/src/test/java/org/sonar/python/checks/SetDuplicateKeyCheckTest.java create mode 100644 python-checks/src/test/resources/checks/setDuplicateKey.py diff --git a/python-checks/src/main/java/org/sonar/python/checks/AbstractDuplicateKeyCheck.java b/python-checks/src/main/java/org/sonar/python/checks/AbstractDuplicateKeyCheck.java new file mode 100644 index 0000000000..cc9dce59ba --- /dev/null +++ b/python-checks/src/main/java/org/sonar/python/checks/AbstractDuplicateKeyCheck.java @@ -0,0 +1,108 @@ +/* + * SonarQube Python Plugin + * Copyright (C) 2011-2020 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * 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.python.checks; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.List; +import java.util.Locale; +import java.util.stream.Collectors; +import org.sonar.plugins.python.api.PythonSubscriptionCheck; +import org.sonar.plugins.python.api.tree.Expression; +import org.sonar.plugins.python.api.tree.Name; +import org.sonar.plugins.python.api.tree.NumericLiteral; +import org.sonar.plugins.python.api.tree.StringElement; +import org.sonar.plugins.python.api.tree.StringLiteral; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.plugins.python.api.tree.Tuple; + +public abstract class AbstractDuplicateKeyCheck extends PythonSubscriptionCheck { + + boolean isSameKey(Expression key, Expression comparedKey) { + if (key.is(Tree.Kind.TUPLE) && comparedKey.is(Tree.Kind.TUPLE)) { + return areEquivalentTuples((Tuple) key, (Tuple) comparedKey); + } + if (key.is(Tree.Kind.STRING_LITERAL) && comparedKey.is(Tree.Kind.STRING_LITERAL)) { + return areEquivalentStringLiterals((StringLiteral) key, (StringLiteral) comparedKey); + } + if (isANumber(key) && isANumber(comparedKey)) { + return areEquivalentNumbers(key, comparedKey); + } + return !key.is(Tree.Kind.CALL_EXPR) && CheckUtils.areEquivalent(key, comparedKey); + } + + private boolean areEquivalentTuples(Tuple key, Tuple comparedKey) { + List first = key.elements(); + List second = comparedKey.elements(); + if (first.size() != second.size()) { + return false; + } + for (int i = 0; i < first.size(); i++) { + if (!isSameKey(first.get(i), second.get(i))) { + return false; + } + } + return true; + } + + private boolean areEquivalentNumbers(Tree key, Tree comparedKey) { + // BigDecimal#compareTo is required as equals() returns true only with identical scales + return toBigDecimal(key).compareTo(toBigDecimal(comparedKey)) == 0; + } + + private BigDecimal toBigDecimal(Tree numberTree) { + if (numberTree.is(Tree.Kind.NUMERIC_LITERAL)) { + return parseAsBigDecimal(((NumericLiteral) numberTree).valueAsString()); + } + return ((Name) numberTree).name().equals("True") ? BigDecimal.ONE : BigDecimal.ZERO; + } + + private static boolean areEquivalentStringLiterals(StringLiteral key, StringLiteral comparedKey) { + if (key.stringElements().stream().anyMatch(StringElement::isInterpolated) || comparedKey.stringElements().stream().anyMatch(StringElement::isInterpolated)) { + return false; + } + if (key.trimmedQuotesValue().equals(comparedKey.trimmedQuotesValue())) { + String keyWithPrefixes = key.stringElements().stream() + .map(s -> s.prefix().toLowerCase(Locale.ENGLISH) + s.trimmedQuotesValue()).collect(Collectors.joining()); + String comparedKeyWithPrefixes = comparedKey.stringElements().stream() + .map(s -> s.prefix().toLowerCase(Locale.ENGLISH) + s.trimmedQuotesValue()).collect(Collectors.joining()); + return keyWithPrefixes.equals(comparedKeyWithPrefixes); + } + return false; + } + + public BigDecimal parseAsBigDecimal(String numberLiteralValue) { + String numberValue = numberLiteralValue.replace("_", ""); + if (numberValue.startsWith("0b") || numberValue.startsWith("0B")) { + return new BigDecimal(new BigInteger(numberValue.substring(2), 2)); + } + if (numberValue.startsWith("0o") || numberValue.startsWith("0O")) { + return new BigDecimal(new BigInteger(numberValue.substring(2), 8)); + } + if (numberValue.startsWith("0x") || numberValue.startsWith("0X")) { + return new BigDecimal(new BigInteger(numberValue.substring(2), 16)); + } + return new BigDecimal(numberValue); + } + + private static boolean isANumber(Tree tree) { + return tree.is(Tree.Kind.NUMERIC_LITERAL) || (tree.is(Tree.Kind.NAME) && (((Name) tree).name().equals("True") || ((Name) tree).name().equals("False"))); + } +} diff --git a/python-checks/src/main/java/org/sonar/python/checks/CheckList.java b/python-checks/src/main/java/org/sonar/python/checks/CheckList.java index 759b1c38b1..c55b683298 100644 --- a/python-checks/src/main/java/org/sonar/python/checks/CheckList.java +++ b/python-checks/src/main/java/org/sonar/python/checks/CheckList.java @@ -170,6 +170,7 @@ public static Iterable getChecks() { SecureCookieCheck.class, SecureModeEncryptionAlgorithmsCheck.class, SelfAssignmentCheck.class, + SetDuplicateKeyCheck.class, SillyEqualityCheck.class, SillyIdentityCheck.class, SpecialMethodParamListCheck.class, diff --git a/python-checks/src/main/java/org/sonar/python/checks/DictionaryDuplicateKeyCheck.java b/python-checks/src/main/java/org/sonar/python/checks/DictionaryDuplicateKeyCheck.java index aedd9be7c2..1ec89ef122 100644 --- a/python-checks/src/main/java/org/sonar/python/checks/DictionaryDuplicateKeyCheck.java +++ b/python-checks/src/main/java/org/sonar/python/checks/DictionaryDuplicateKeyCheck.java @@ -19,29 +19,19 @@ */ package org.sonar.python.checks; -import java.math.BigDecimal; -import java.math.BigInteger; import java.util.ArrayList; import java.util.HashSet; import java.util.List; -import java.util.Locale; import java.util.Set; -import java.util.stream.Collectors; import org.sonar.check.Rule; -import org.sonar.plugins.python.api.PythonSubscriptionCheck; import org.sonar.plugins.python.api.tree.DictionaryLiteral; import org.sonar.plugins.python.api.tree.DictionaryLiteralElement; import org.sonar.plugins.python.api.tree.Expression; import org.sonar.plugins.python.api.tree.KeyValuePair; -import org.sonar.plugins.python.api.tree.Name; -import org.sonar.plugins.python.api.tree.NumericLiteral; -import org.sonar.plugins.python.api.tree.StringElement; -import org.sonar.plugins.python.api.tree.StringLiteral; import org.sonar.plugins.python.api.tree.Tree; -import org.sonar.plugins.python.api.tree.Tuple; @Rule(key = "S5780") -public class DictionaryDuplicateKeyCheck extends PythonSubscriptionCheck { +public class DictionaryDuplicateKeyCheck extends AbstractDuplicateKeyCheck { @Override public void initialize(Context context) { @@ -80,75 +70,4 @@ private List findIdenticalKeys(int startIndex, List first = key.elements(); - List second = comparedKey.elements(); - if (first.size() != second.size()) { - return false; - } - for (int i = 0; i < first.size(); i++) { - if (!isSameKey(first.get(i), second.get(i))) { - return false; - } - } - return true; - } - - private boolean areEquivalentNumbers(Tree key, Tree comparedKey) { - // BigDecimal#compareTo is required as equals() returns true only with identical scales - return toBigDecimal(key).compareTo(toBigDecimal(comparedKey)) == 0; - } - - private BigDecimal toBigDecimal(Tree numberTree) { - if (numberTree.is(Tree.Kind.NUMERIC_LITERAL)) { - return parseAsBigDecimal(((NumericLiteral) numberTree).valueAsString()); - } - return ((Name) numberTree).name().equals("True") ? BigDecimal.ONE : BigDecimal.ZERO; - } - - private static boolean areEquivalentStringLiterals(StringLiteral key, StringLiteral comparedKey) { - if (key.stringElements().stream().anyMatch(StringElement::isInterpolated) || comparedKey.stringElements().stream().anyMatch(StringElement::isInterpolated)) { - return false; - } - if (key.trimmedQuotesValue().equals(comparedKey.trimmedQuotesValue())) { - String keyWithPrefixes = key.stringElements().stream() - .map(s -> s.prefix().toLowerCase(Locale.ENGLISH) + s.trimmedQuotesValue()).collect(Collectors.joining()); - String comparedKeyWithPrefixes = comparedKey.stringElements().stream() - .map(s -> s.prefix().toLowerCase(Locale.ENGLISH) + s.trimmedQuotesValue()).collect(Collectors.joining()); - return keyWithPrefixes.equals(comparedKeyWithPrefixes); - } - return false; - } - - public BigDecimal parseAsBigDecimal(String numberLiteralValue) { - String numberValue = numberLiteralValue.replace("_", ""); - if (numberValue.startsWith("0b") || numberValue.startsWith("0B")) { - return new BigDecimal(new BigInteger(numberValue.substring(2), 2)); - } - if (numberValue.startsWith("0o") || numberValue.startsWith("0O")) { - return new BigDecimal(new BigInteger(numberValue.substring(2), 8)); - } - if (numberValue.startsWith("0x") || numberValue.startsWith("0X")) { - return new BigDecimal(new BigInteger(numberValue.substring(2), 16)); - } - return new BigDecimal(numberValue); - } - - private static boolean isANumber(Tree tree) { - return tree.is(Tree.Kind.NUMERIC_LITERAL) || (tree.is(Tree.Kind.NAME) && (((Name) tree).name().equals("True") || ((Name) tree).name().equals("False"))); - } } diff --git a/python-checks/src/main/java/org/sonar/python/checks/SetDuplicateKeyCheck.java b/python-checks/src/main/java/org/sonar/python/checks/SetDuplicateKeyCheck.java new file mode 100644 index 0000000000..e193503cea --- /dev/null +++ b/python-checks/src/main/java/org/sonar/python/checks/SetDuplicateKeyCheck.java @@ -0,0 +1,68 @@ +/* + * SonarQube Python Plugin + * Copyright (C) 2011-2020 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * 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.python.checks; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import org.sonar.check.Rule; +import org.sonar.plugins.python.api.tree.Expression; +import org.sonar.plugins.python.api.tree.SetLiteral; +import org.sonar.plugins.python.api.tree.Tree; + +@Rule(key = "S5781") +public class SetDuplicateKeyCheck extends AbstractDuplicateKeyCheck { + + @Override + public void initialize(Context context) { + context.registerSyntaxNodeConsumer(Tree.Kind.SET_LITERAL, ctx -> { + SetLiteral setLiteral = (SetLiteral) ctx.syntaxNode(); + Set issueIndexes = new HashSet<>(); + if (setLiteral.elements().size() > 100) { + return; + } + for (int i = 0; i < setLiteral.elements().size(); i++) { + if (issueIndexes.contains(i)) { + continue; + } + Expression key = setLiteral.elements().get(i); + List duplicateKeys = findIdenticalKeys(i, setLiteral.elements(), issueIndexes); + if (!duplicateKeys.isEmpty()) { + PreciseIssue issue = ctx.addIssue(key, "Change or remove duplicates of this key."); + duplicateKeys.forEach(d -> issue.secondary(d, "Duplicate key")); + } + } + }); + } + + private List findIdenticalKeys(int startIndex, List elements, Set issueIndexes) { + Expression key = elements.get(startIndex); + List duplicates = new ArrayList<>(); + for (int i = startIndex + 1; i < elements.size(); i++) { + Expression comparedKey = elements.get(i); + if (isSameKey(key, comparedKey)) { + issueIndexes.add(i); + duplicates.add(comparedKey); + } + } + return duplicates; + } +} diff --git a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S5781.html b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S5781.html new file mode 100644 index 0000000000..6283530912 --- /dev/null +++ b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S5781.html @@ -0,0 +1,22 @@ +

A set cannot have two identical values. When a value is repeated in a set literal, only the last occurence will remain. Thus duplicate values +should be either modified or removed.

+

This rule raises an issue when the same value is used multiple times as a value in a set literal.

+

Noncompliant Code Example

+
+{"one", "two", "one"}  # Noncompliant
+
+def func(a1, a2, a3):
+    {a1, a2, a1}  # Noncompliant.
+
+

Compliant Solution

+
+{"one", "two", "three"}
+
+def func(a1, a2, a3):
+    {a1, a2, a3}
+
+

See

+ + diff --git a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S5781.json b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S5781.json new file mode 100644 index 0000000000..1b4f024f9a --- /dev/null +++ b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/S5781.json @@ -0,0 +1,12 @@ +{ + "title": "Expressions creating sets should not have duplicate values", + "type": "BUG", + "status": "ready", + "tags": [ + + ], + "defaultSeverity": "Major", + "ruleSpecification": "RSPEC-5781", + "sqKey": "S5781", + "scope": "All" +} diff --git a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/Sonar_way_profile.json b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/Sonar_way_profile.json index b1b4509ea4..a70a26fde9 100644 --- a/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/Sonar_way_profile.json +++ b/python-checks/src/main/resources/org/sonar/l10n/py/rules/python/Sonar_way_profile.json @@ -112,6 +112,7 @@ "S5747", "S5754", "S5780", + "S5781", "S5795", "S5796", "S5797" diff --git a/python-checks/src/test/java/org/sonar/python/checks/SetDuplicateKeyCheckTest.java b/python-checks/src/test/java/org/sonar/python/checks/SetDuplicateKeyCheckTest.java new file mode 100644 index 0000000000..9bf6ee27af --- /dev/null +++ b/python-checks/src/test/java/org/sonar/python/checks/SetDuplicateKeyCheckTest.java @@ -0,0 +1,31 @@ +/* + * SonarQube Python Plugin + * Copyright (C) 2011-2020 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * 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.python.checks; + +import org.junit.Test; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class SetDuplicateKeyCheckTest { + + @Test + public void test() { + PythonCheckVerifier.verify("src/test/resources/checks/setDuplicateKey.py", new SetDuplicateKeyCheck()); + } +} diff --git a/python-checks/src/test/resources/checks/setDuplicateKey.py b/python-checks/src/test/resources/checks/setDuplicateKey.py new file mode 100644 index 0000000000..126483c670 --- /dev/null +++ b/python-checks/src/test/resources/checks/setDuplicateKey.py @@ -0,0 +1,96 @@ +def strings(): + {"one", "two"} + {"one", "two", "one"} # Noncompliant {{Change or remove duplicates of this key.}} + #^^^^^ ^^^^^< + {"one", "two", 'one'} # Noncompliant + {"""multi + line""", # Noncompliant@-1 + "two", + """multi + line"""} + + # We only raise if the strings have same values & prefixes, even if they would eventually evaluate to the same value + {"one", "two", u"one"} # FN (ok) + {"one", "two", r"one"} # FN (ok) + {"on" "e", "two", "o" "ne"} # Noncompliant + {"on" r"e", "two", "on" r"e"} # Noncompliant + {"on" r"e", "two", "o" r"ne"} # FN (ok) + + # No issue on f-strings to avoid any risk of FP + p = 1 + {f"one{p}", "two", f"one{p}"} # FN (ok) + {f"one{p()}", "two", f"one{p()}"} # FN (ok) + +def numbers(): + {1, 2, 1} # Noncompliant + {1.0, 2.0, 1.0} # Noncompliant + {0o1, 0o2, 0O1} # Noncompliant + {0x1, 0x3, 0X1} # Noncompliant + {0b1, 0o2, 0B1} # Noncompliant + {True, False, True} # Noncompliant + +def mixed_types(): + {1.0, 2.0, 0o1} # Noncompliant + {1, 2, 1.0} # Noncompliant + # True == 1 + {1, 2, True} # Noncompliant + # False == 0 + {0, 2, False} # Noncompliant + {"1", 1, "2"} # OK + + +def unpacking_expressions(): + dict = {1} + {1, *dict} # FN + {1, *{1}} # FN + + +def other_cases(): + {None, None} # Noncompliant + {(1, "2"), 2, (1, "2")} # Noncompliant + {(1, "2"), 2, ("2", 1)} + # Raises TypeError + {{"a": 1}, {"a": 1}} # Noncompliant + {1} + {frozenset({1}), frozenset({1})} # FN + +def repeated_variables(a1, a2, a3): + {a1, a2, a1} # Noncompliant + {a1.b, a2, a1.b} # Noncompliant + {func, a2, func} # Noncompliant + + [{a, a} for a in range(10)] # Noncompliant + + class MyClass: + pass + + {MyClass, a2, MyClass} # Noncompliant + {MyClass.__doc__, a2, MyClass.__doc__} # Noncompliant + + {MyClass(), a2, MyClass()} # OK + {a1(), a2, a1()} # OK + {func(1, 2, 3), a2, func(1, 2, 3)} # OK + +def tuples(): + {(2, bar()), (2, bar())} # function calls + { (0o10, 'a'), (8, "a")} # Noncompliant + { (0o10, 'a'), (8, "a", "b")} # OK + { (1,), 1 } # OK + + +def large_dict_literal(): + # Accepted FNs to avoid performance issues + { + "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", + "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", + "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", + "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", + "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", + "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", + "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", + "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", + "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", + "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", + "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", + "a", "b" + } From 3b79611a0e06f2041aaae0688d9c40ad6ef6b5bc Mon Sep 17 00:00:00 2001 From: Guillaume Dequenne Date: Tue, 19 May 2020 09:31:22 +0200 Subject: [PATCH 2/2] Add variable to represent size threshold for dict/set literals --- .../org/sonar/python/checks/AbstractDuplicateKeyCheck.java | 3 +++ .../org/sonar/python/checks/DictionaryDuplicateKeyCheck.java | 2 +- .../java/org/sonar/python/checks/SetDuplicateKeyCheck.java | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/python-checks/src/main/java/org/sonar/python/checks/AbstractDuplicateKeyCheck.java b/python-checks/src/main/java/org/sonar/python/checks/AbstractDuplicateKeyCheck.java index cc9dce59ba..8c9ffd1b7f 100644 --- a/python-checks/src/main/java/org/sonar/python/checks/AbstractDuplicateKeyCheck.java +++ b/python-checks/src/main/java/org/sonar/python/checks/AbstractDuplicateKeyCheck.java @@ -35,6 +35,9 @@ public abstract class AbstractDuplicateKeyCheck extends PythonSubscriptionCheck { + // Avoid performance issues for big dictionary/set literals + static final int SIZE_THRESHOLD = 100; + boolean isSameKey(Expression key, Expression comparedKey) { if (key.is(Tree.Kind.TUPLE) && comparedKey.is(Tree.Kind.TUPLE)) { return areEquivalentTuples((Tuple) key, (Tuple) comparedKey); diff --git a/python-checks/src/main/java/org/sonar/python/checks/DictionaryDuplicateKeyCheck.java b/python-checks/src/main/java/org/sonar/python/checks/DictionaryDuplicateKeyCheck.java index 1ec89ef122..07bf8b54a6 100644 --- a/python-checks/src/main/java/org/sonar/python/checks/DictionaryDuplicateKeyCheck.java +++ b/python-checks/src/main/java/org/sonar/python/checks/DictionaryDuplicateKeyCheck.java @@ -38,7 +38,7 @@ public void initialize(Context context) { context.registerSyntaxNodeConsumer(Tree.Kind.DICTIONARY_LITERAL, ctx -> { DictionaryLiteral dictionaryLiteral = (DictionaryLiteral) ctx.syntaxNode(); Set issueIndexes = new HashSet<>(); - if (dictionaryLiteral.elements().size() > 100) { + if (dictionaryLiteral.elements().size() > SIZE_THRESHOLD) { return; } for (int i = 0; i < dictionaryLiteral.elements().size(); i++) { diff --git a/python-checks/src/main/java/org/sonar/python/checks/SetDuplicateKeyCheck.java b/python-checks/src/main/java/org/sonar/python/checks/SetDuplicateKeyCheck.java index e193503cea..eda6a6294d 100644 --- a/python-checks/src/main/java/org/sonar/python/checks/SetDuplicateKeyCheck.java +++ b/python-checks/src/main/java/org/sonar/python/checks/SetDuplicateKeyCheck.java @@ -36,7 +36,7 @@ public void initialize(Context context) { context.registerSyntaxNodeConsumer(Tree.Kind.SET_LITERAL, ctx -> { SetLiteral setLiteral = (SetLiteral) ctx.syntaxNode(); Set issueIndexes = new HashSet<>(); - if (setLiteral.elements().size() > 100) { + if (setLiteral.elements().size() > SIZE_THRESHOLD) { return; } for (int i = 0; i < setLiteral.elements().size(); i++) {