From 383db78fa0c7bed5c40a9d5557ac82436d695c88 Mon Sep 17 00:00:00 2001 From: jberque Date: Thu, 10 Feb 2022 16:58:24 +0100 Subject: [PATCH 001/119] add Torch Free Rule in native android analyser --- .../java/io/ecocode/java/JavaCheckList.java | 13 ++--- .../constant/ArgumentValueOnMethodCheck.java | 3 +- .../java/checks/sobriety/TorchFreeRule.java | 48 +++++++++++++++++++ .../l10n/java/rules/squid/ESOB012_java.html | 14 ++++++ .../l10n/java/rules/squid/ESOB012_java.json | 15 ++++++ .../rules/squid/ecocode_java_profile.json | 1 + .../test/files/sobriety/TorchFreeCheck.java | 27 +++++++++++ .../ecocode/java/JavaRulesDefinitionTest.java | 6 +++ .../checks/sobriety/TorchFreeRuleTest.java | 14 ++++++ 9 files changed, 132 insertions(+), 9 deletions(-) create mode 100644 sonarqube-plugin-greenit/native-analyzer/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/TorchFreeRule.java create mode 100644 sonarqube-plugin-greenit/native-analyzer/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ESOB012_java.html create mode 100644 sonarqube-plugin-greenit/native-analyzer/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ESOB012_java.json create mode 100644 sonarqube-plugin-greenit/native-analyzer/android-plugin/src/test/files/sobriety/TorchFreeCheck.java create mode 100644 sonarqube-plugin-greenit/native-analyzer/android-plugin/src/test/java/io/ecocode/java/checks/sobriety/TorchFreeRuleTest.java diff --git a/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/main/java/io/ecocode/java/JavaCheckList.java b/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/main/java/io/ecocode/java/JavaCheckList.java index d520ce182..a4b1f34e4 100644 --- a/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/main/java/io/ecocode/java/JavaCheckList.java +++ b/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/main/java/io/ecocode/java/JavaCheckList.java @@ -20,17 +20,13 @@ package io.ecocode.java; import io.ecocode.java.checks.bottleneck.InternetInTheLoopRule; +import io.ecocode.java.checks.bottleneck.WifiMulticastLockRule; import io.ecocode.java.checks.idleness.*; +import io.ecocode.java.checks.leakage.*; import io.ecocode.java.checks.optimized_api.BluetoothLowEnergyRule; import io.ecocode.java.checks.optimized_api.FusedLocationRule; -import io.ecocode.java.checks.sobriety.*; import io.ecocode.java.checks.power.ChargeAwarenessRule; -import io.ecocode.java.checks.sobriety.BrightnessOverrideRule; -import io.ecocode.java.checks.leakage.*; -import io.ecocode.java.checks.sobriety.ThriftyGeolocationMinDistanceRule; -import io.ecocode.java.checks.sobriety.ThriftyGeolocationMinTimeRule; -import io.ecocode.java.checks.sobriety.ThriftyMotionSensorRule; -import io.ecocode.java.checks.bottleneck.WifiMulticastLockRule; +import io.ecocode.java.checks.sobriety.*; import org.sonar.plugins.java.api.JavaCheck; import java.util.ArrayList; @@ -75,7 +71,8 @@ public static List> getJavaChecks() { ThriftyGeolocationMinTimeRule.class, ThriftyGeolocationMinDistanceRule.class, ChargeAwarenessRule.class, - VibrationFreeRule.class + VibrationFreeRule.class, + TorchFreeRule.class )); } diff --git a/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/main/java/io/ecocode/java/checks/helpers/constant/ArgumentValueOnMethodCheck.java b/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/main/java/io/ecocode/java/checks/helpers/constant/ArgumentValueOnMethodCheck.java index 253bd6775..9e8de0ba1 100644 --- a/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/main/java/io/ecocode/java/checks/helpers/constant/ArgumentValueOnMethodCheck.java +++ b/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/main/java/io/ecocode/java/checks/helpers/constant/ArgumentValueOnMethodCheck.java @@ -111,7 +111,8 @@ private void handleArgument(ExpressionTree argument) { || argument.is(Tree.Kind.INT_LITERAL) || argument.is(Tree.Kind.LONG_LITERAL) || argument.is(Tree.Kind.FLOAT_LITERAL) - || argument.is(Tree.Kind.DOUBLE_LITERAL)) { + || argument.is(Tree.Kind.DOUBLE_LITERAL) + || argument.is(Tree.Kind.BOOLEAN_LITERAL)) { checkConstantValue(argument.asConstant(), argument, constantValueToCheck); } else { checkArgumentComplexType(argument); diff --git a/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/TorchFreeRule.java b/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/TorchFreeRule.java new file mode 100644 index 000000000..5bb4d8ea2 --- /dev/null +++ b/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/TorchFreeRule.java @@ -0,0 +1,48 @@ +/* + * ecoCode SonarQube Plugin + * Copyright (C) 2020-2021 Snapp' - Université de Pau et des Pays de l'Adour + * mailto: contact@ecocode.io + * + * 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 io.ecocode.java.checks.sobriety; + +import io.ecocode.java.checks.helpers.constant.ArgumentValueOnMethodCheck; +import org.sonar.check.Rule; +import org.sonar.plugins.java.api.tree.Tree; + +import java.util.Optional; + +@Rule(key = "ESOB012", name = "ecocodeTorchFree") +public class TorchFreeRule extends ArgumentValueOnMethodCheck { + + public TorchFreeRule() { + super("setTorchMode", "android.hardware.camera2.CameraManager", true, 1); + } + + @Override + public String getMessage() { + return "Turning on the torch mode programmatically must absolutely be avoided."; + } + + @Override + protected void checkConstantValue(Optional optionalConstantValue, Tree reportTree, Object constantValueToCheck) { + if (optionalConstantValue.isPresent() && optionalConstantValue.get().equals(constantValueToCheck)) { + reportIssue(reportTree, getMessage()); + } + } + +} diff --git a/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ESOB012_java.html b/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ESOB012_java.html new file mode 100644 index 000000000..49e670325 --- /dev/null +++ b/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ESOB012_java.html @@ -0,0 +1,14 @@ + +

Turning on the torch mode programmatically with CameraManager#setTorchMode(..., true) must absolutely be + avoided because the flashlight is one of the most energy-intensive component.

+

Noncompliant Code Example

+
+ CameraManager camManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
+        String cameraId = null;
+        try {
+            cameraId = camManager.getCameraIdList()[0];
+            camManager.setTorchMode(cameraId, true);
+        } catch (CameraAccessException e) {
+            e.printStackTrace();
+        }
+
\ No newline at end of file diff --git a/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ESOB012_java.json b/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ESOB012_java.json new file mode 100644 index 000000000..a4847e253 --- /dev/null +++ b/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ESOB012_java.json @@ -0,0 +1,15 @@ +{ + "title": "Sobriety: Torch Free", + "type": "CODE_SMELL", + "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "5min" + }, + "tags": [ + "sobriety", + "environment", + "ecocode" + ], + "defaultSeverity": "Minor" +} \ No newline at end of file diff --git a/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ecocode_java_profile.json b/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ecocode_java_profile.json index dd420838e..33b3bd855 100644 --- a/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ecocode_java_profile.json +++ b/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ecocode_java_profile.json @@ -15,6 +15,7 @@ "ESOB008", "ESOB010", "ESOB011", + "ESOB012", "EOPT001", "EOPT002", "EIDL001", diff --git a/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/test/files/sobriety/TorchFreeCheck.java b/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/test/files/sobriety/TorchFreeCheck.java new file mode 100644 index 000000000..60a5fdefc --- /dev/null +++ b/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/test/files/sobriety/TorchFreeCheck.java @@ -0,0 +1,27 @@ +package android.hardware.camera2; + +public final class CameraManager { + + public void test() { + CameraManager camManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); + String cameraId = null; + try { + cameraId = camManager.getCameraIdList()[0]; + camManager.setTorchMode(cameraId, true); // Noncompliant {{Turning on the torch mode programmatically must absolutely be avoided.}} + } catch (CameraAccessException e) { + e.printStackTrace(); + } + } + + private Service getSystemService(String string) { + return null; + } + + private String[] getCameraIdList() { + return new String[]{"0", "1", "2"}; + } + + public void setTorchMode(String cameraId, boolean enabled) throws CameraAccessException { + //torch manipulation + } +} \ No newline at end of file diff --git a/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/test/java/io/ecocode/java/JavaRulesDefinitionTest.java b/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/test/java/io/ecocode/java/JavaRulesDefinitionTest.java index c2f7e93ee..2032c717f 100644 --- a/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/test/java/io/ecocode/java/JavaRulesDefinitionTest.java +++ b/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/test/java/io/ecocode/java/JavaRulesDefinitionTest.java @@ -185,6 +185,12 @@ private void assertRuleProperties(Repository repository) { assertThat(vibrationFreeRule.debtRemediationFunction().type()).isEqualTo(Type.CONSTANT_ISSUE); assertThat(vibrationFreeRule.type()).isEqualTo(RuleType.CODE_SMELL); + Rule torchFreeRule = repository.rule("ESOB012"); + assertThat(torchFreeRule).isNotNull(); + assertThat(torchFreeRule.name()).isEqualTo("Sobriety: Torch Free"); + assertThat(torchFreeRule.debtRemediationFunction().type()).isEqualTo(Type.CONSTANT_ISSUE); + assertThat(torchFreeRule.type()).isEqualTo(RuleType.CODE_SMELL); + Rule chargeAwarenessRule = repository.rule("EPOW004"); assertThat(chargeAwarenessRule).isNotNull(); assertThat(chargeAwarenessRule.name()).isEqualTo("Power: Charge Awareness"); diff --git a/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/test/java/io/ecocode/java/checks/sobriety/TorchFreeRuleTest.java b/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/test/java/io/ecocode/java/checks/sobriety/TorchFreeRuleTest.java new file mode 100644 index 000000000..a12c4edef --- /dev/null +++ b/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/test/java/io/ecocode/java/checks/sobriety/TorchFreeRuleTest.java @@ -0,0 +1,14 @@ +package io.ecocode.java.checks.sobriety; + +import org.junit.Test; +import org.sonar.java.checks.verifier.JavaCheckVerifier; + +public class TorchFreeRuleTest { + + @Test + public void verify() { + JavaCheckVerifier.newVerifier().onFile("src/test/files/sobriety/TorchFreeCheck.java") + .withCheck(new TorchFreeRule()) + .verifyIssues(); + } +} From 68315ee1480216d54c624a10dc712ca6715d6818 Mon Sep 17 00:00:00 2001 From: jberque Date: Thu, 10 Feb 2022 17:29:52 +0100 Subject: [PATCH 002/119] torch_free_rule :: add rule description --- .../java/io/ecocode/java/checks/sobriety/TorchFreeRule.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/TorchFreeRule.java b/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/TorchFreeRule.java index 5bb4d8ea2..b69c789a4 100644 --- a/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/TorchFreeRule.java +++ b/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/TorchFreeRule.java @@ -26,6 +26,10 @@ import java.util.Optional; +/** + * Check the call of the method "setTorchMode" from "android.hardware.camera2.CameraManager" + * with the param 1 set to "true". + */ @Rule(key = "ESOB012", name = "ecocodeTorchFree") public class TorchFreeRule extends ArgumentValueOnMethodCheck { From d8a5b741fb5cdd48d73ede9200afb667d36dc417 Mon Sep 17 00:00:00 2001 From: jberque Date: Thu, 10 Feb 2022 17:31:30 +0100 Subject: [PATCH 003/119] torch_free_rule :: add new line at the end of files --- .../resources/org/sonar/l10n/java/rules/squid/ESOB012_java.html | 2 +- .../resources/org/sonar/l10n/java/rules/squid/ESOB012_java.json | 2 +- .../android-plugin/src/test/files/sobriety/TorchFreeCheck.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ESOB012_java.html b/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ESOB012_java.html index 49e670325..8d7bb6c60 100644 --- a/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ESOB012_java.html +++ b/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ESOB012_java.html @@ -11,4 +11,4 @@

Noncompliant Code Example

} catch (CameraAccessException e) { e.printStackTrace(); } - \ No newline at end of file + diff --git a/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ESOB012_java.json b/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ESOB012_java.json index a4847e253..539b7fdf3 100644 --- a/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ESOB012_java.json +++ b/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ESOB012_java.json @@ -12,4 +12,4 @@ "ecocode" ], "defaultSeverity": "Minor" -} \ No newline at end of file +} diff --git a/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/test/files/sobriety/TorchFreeCheck.java b/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/test/files/sobriety/TorchFreeCheck.java index 60a5fdefc..ac6f6e3e0 100644 --- a/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/test/files/sobriety/TorchFreeCheck.java +++ b/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/test/files/sobriety/TorchFreeCheck.java @@ -24,4 +24,4 @@ private String[] getCameraIdList() { public void setTorchMode(String cameraId, boolean enabled) throws CameraAccessException { //torch manipulation } -} \ No newline at end of file +} From cc77a6a6674d6c2992623f5d402267fa594de0d5 Mon Sep 17 00:00:00 2001 From: "Antoine.Meheut" <34522927+AntoineMeheut@users.noreply.github.com> Date: Wed, 6 Apr 2022 22:22:36 +0200 Subject: [PATCH 004/119] Create COPYING Proposal to add the COPYING file of the GNU General Public License v3.0 --- COPYING | 674 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 674 insertions(+) create mode 100644 COPYING diff --git a/COPYING b/COPYING new file mode 100644 index 000000000..f288702d2 --- /dev/null +++ b/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. From efb7596c4c2e4aa8d3ebb13f5147995917707161 Mon Sep 17 00:00:00 2001 From: u$f Date: Wed, 1 Jun 2022 23:23:34 +0200 Subject: [PATCH 005/119] sql checks --- .../java/checks/AvoidFullSQLRequest.java | 21 +++++++++---------- .../java/checks/AvoidSQLRequestInLoop.java | 7 ++++--- .../test/files/AvoidFullSQLRequestCheck.java | 9 ++++++++ 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidFullSQLRequest.java b/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidFullSQLRequest.java index dd5219120..29d2bf3f1 100644 --- a/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidFullSQLRequest.java +++ b/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidFullSQLRequest.java @@ -1,7 +1,11 @@ package fr.cnumr.java.checks; -import java.util.Arrays; +import static java.util.Collections.singletonList; +import static java.util.regex.Pattern.CASE_INSENSITIVE; +import static java.util.regex.Pattern.compile; + import java.util.List; +import java.util.function.Predicate; import org.sonar.check.Priority; import org.sonar.check.Rule; @@ -19,23 +23,18 @@ public class AvoidFullSQLRequest extends IssuableSubscriptionVisitor { protected static final String MESSAGERULE = "Don't use the query SELECT * FROM"; - private static final String REGEXPSELECTFROM = "(?i).*select.*\\*.*from.*"; + private static final Predicate SELECT_FROM_REGEXP = + compile("select\\s*\\*\\s*from", CASE_INSENSITIVE).asPredicate(); //simple regexp, more precision @Override public List nodesToVisit() { - return Arrays.asList(Tree.Kind.STRING_LITERAL); + return singletonList(Tree.Kind.STRING_LITERAL); } @Override public void visitNode(Tree tree) { - boolean isSelectFrom = false; - - if (tree.is(Kind.STRING_LITERAL,Kind.TEXT_BLOCK)) { - LiteralTree literal = (LiteralTree) tree; - isSelectFrom = literal.value().matches(REGEXPSELECTFROM); - } - - if (isSelectFrom) { + String value = ((LiteralTree) tree).value(); + if (SELECT_FROM_REGEXP.test(value)) { reportIssue(tree, MESSAGERULE); } } diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidSQLRequestInLoop.java b/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidSQLRequestInLoop.java index f51ab4a03..7b33712ec 100644 --- a/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidSQLRequestInLoop.java +++ b/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidSQLRequestInLoop.java @@ -5,7 +5,6 @@ import java.util.Arrays; import java.util.List; -import org.apache.tomcat.util.descriptor.web.MessageDestinationRef; import org.sonar.check.Priority; import org.sonar.check.Rule; import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; @@ -24,7 +23,9 @@ public class AvoidSQLRequestInLoop extends IssuableSubscriptionVisitor { @Override public List nodesToVisit() { - return Arrays.asList(Tree.Kind.FOR_EACH_STATEMENT, Tree.Kind.FOR_STATEMENT, Tree.Kind.WHILE_STATEMENT); + return Arrays.asList( + Tree.Kind.FOR_EACH_STATEMENT, Tree.Kind.FOR_STATEMENT, + Tree.Kind.WHILE_STATEMENT, Tree.Kind.DO_STATEMENT); } @Override @@ -42,7 +43,7 @@ private class AvoidSQLRequestInLoopVisitor extends BaseTreeVisitor { MethodMatchers.create().ofSubTypes("org.hibernate.Session").names("createQuery", "createSQLQuery") .withAnyParameters().build(), MethodMatchers.create().ofSubTypes(JAVA_SQL_STATEMENT) - .names("executeQuery", "execute", "executeUpdate", "executeLargeUpdate", "addBatch") + .names("executeQuery", "execute", "executeUpdate", "executeLargeUpdate") // addBatch is recommended .withAnyParameters().build(), MethodMatchers.create().ofSubTypes(JAVA_SQL_CONNECTION) .names("prepareStatement", "prepareCall", "nativeSQL") diff --git a/src/java-plugin/src/test/files/AvoidFullSQLRequestCheck.java b/src/java-plugin/src/test/files/AvoidFullSQLRequestCheck.java index 3c01e9f58..52a9bc391 100644 --- a/src/java-plugin/src/test/files/AvoidFullSQLRequestCheck.java +++ b/src/java-plugin/src/test/files/AvoidFullSQLRequestCheck.java @@ -1,5 +1,7 @@ package fr.cnumr.java.checks; +import java.util.regex.Pattern; + class AvoidFullSQLRequestCheck { AvoidFullSQLRequestCheck(AvoidFullSQLRequestCheck mc) { } @@ -7,6 +9,9 @@ class AvoidFullSQLRequestCheck { public void literalSQLrequest() { dummyCall(" sElEcT * fRoM myTable"); // Noncompliant dummyCall(" sElEcT user fRoM myTable"); + + dummyCall("SELECTABLE 2*2 FROMAGE"); //not sql + dummyCall("SELECT *FROM table"); // Noncompliant } @@ -15,9 +20,13 @@ public void variableSQLrequest() { String requestCompiliant = " SeLeCt user FrOm myTable"; dummyCall(requestNonCompiliant); dummyCall(requestCompiliant); + + String noSqlCompiliant = "SELECTABLE 2*2 FROMAGE"; //not sql + String requestNonCompiliant_nSpace = "SELECT *FROM table"; // Noncompliant } private void dummyCall (String request) { } + } \ No newline at end of file From e8967a14ee9508ff177ebac2d3f74cda6390f833 Mon Sep 17 00:00:00 2001 From: OLLIVIER Elodie Date: Thu, 2 Jun 2022 10:29:26 +0200 Subject: [PATCH 006/119] =?UTF-8?q?r=C3=A8gle=20D4-PHP?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/fr/cnumr/php/MyPhpRules.java | 9 +++-- .../AvoidUsingGlobalVariablesCheck.java | 33 ++++++++++++++++ .../fr/cnumr/l10n/php/rules/custom/D4.html | 19 ++++++++++ .../fr/cnumr/l10n/php/rules/custom/D4.json | 13 +++++++ .../java/fr/cnumr/php/MyPhpRulesTest.java | 2 +- .../AvoidUsingGlobalVariablesCheckTest.java | 38 +++++++++++++++++++ .../checks/AvoidUsingGlobalVariablesCheck.php | 16 ++++++++ 7 files changed, 126 insertions(+), 4 deletions(-) create mode 100644 src/php-plugin/src/main/java/fr/cnumr/php/checks/AvoidUsingGlobalVariablesCheck.java create mode 100644 src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/D4.html create mode 100644 src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/D4.json create mode 100644 src/php-plugin/src/test/java/fr/cnumr/php/checks/AvoidUsingGlobalVariablesCheckTest.java create mode 100644 src/php-plugin/src/test/resources/checks/AvoidUsingGlobalVariablesCheck.php diff --git a/src/php-plugin/src/main/java/fr/cnumr/php/MyPhpRules.java b/src/php-plugin/src/main/java/fr/cnumr/php/MyPhpRules.java index 29393a555..8cd1537a4 100644 --- a/src/php-plugin/src/main/java/fr/cnumr/php/MyPhpRules.java +++ b/src/php-plugin/src/main/java/fr/cnumr/php/MyPhpRules.java @@ -21,13 +21,16 @@ import com.google.common.collect.ImmutableList; -import java.util.*; - import fr.cnumr.php.checks.*; import org.sonar.api.server.rule.RulesDefinition; import org.sonar.plugins.php.api.visitors.PHPCustomRuleRepository; import org.sonarsource.analyzer.commons.RuleMetadataLoader; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Objects; +import java.util.Set; + /** * Extension point to define a PHP rule repository. */ @@ -53,7 +56,7 @@ public String repositoryKey() { */ @Override public ImmutableList checkClasses() { - return ImmutableList.of(IncrementCheck.class, AvoidTryCatchFinallyCheck.class, AvoidDoubleQuoteCheck.class, + return ImmutableList.of(AvoidUsingGlobalVariablesCheck.class, IncrementCheck.class, AvoidTryCatchFinallyCheck.class, AvoidDoubleQuoteCheck.class, AvoidFullSQLRequestCheck.class, AvoidSQLRequestInLoopCheck.class, NoFunctionCallWhenDeclaringForLoop.class); } diff --git a/src/php-plugin/src/main/java/fr/cnumr/php/checks/AvoidUsingGlobalVariablesCheck.java b/src/php-plugin/src/main/java/fr/cnumr/php/checks/AvoidUsingGlobalVariablesCheck.java new file mode 100644 index 000000000..a622c1235 --- /dev/null +++ b/src/php-plugin/src/main/java/fr/cnumr/php/checks/AvoidUsingGlobalVariablesCheck.java @@ -0,0 +1,33 @@ +package fr.cnumr.php.checks; + +import org.sonar.check.Priority; +import org.sonar.check.Rule; +import org.sonar.plugins.php.api.tree.declaration.FunctionDeclarationTree; +import org.sonar.plugins.php.api.visitors.PHPVisitorCheck; + +import java.util.regex.Pattern; + +@Rule( + key = "D4", + name = "Developpement", + description = AvoidUsingGlobalVariablesCheck.ERROR_MESSAGE, + priority = Priority.MINOR, + tags = {"bug"}) + +public class AvoidUsingGlobalVariablesCheck extends PHPVisitorCheck { + + public static final String ERROR_MESSAGE = "Prefer local variables to globals"; + public static final String GLOBALS_PATTERN = "^.*(global \\$|\\$GLOBALS).*$"; + private Pattern pattern; + String format = GLOBALS_PATTERN; + @Override + public void init() { + pattern = Pattern.compile(format,Pattern.CASE_INSENSITIVE); + } + @Override + public void visitFunctionDeclaration(FunctionDeclarationTree tree) { + if(pattern.matcher(tree.body().toString()).matches()){ + context().newIssue(this, tree, String.format(ERROR_MESSAGE, tree.body().toString())); + } + } +} diff --git a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/D4.html b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/D4.html new file mode 100644 index 000000000..60ac37cc0 --- /dev/null +++ b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/D4.html @@ -0,0 +1,19 @@ +

+ Prefer local variables as parameters +

+

A l'appel d'une variable globale, le moteur d'interprétation doit vérifier son existence dans tous les scopes, qu'elle dispose d'une valeur, etc. Passer les variables globales en argument de routines les rend locales dans la fonction, permettant ainsi d'économiser du temps de calcul (cycles CPU). +

+

exemple:
+ var aGlobal = new String('Hello');
+ function globalLength(){
+ length = aGlobal.length;
+ console.log(length);
+ }
+ globalLength();
+
+ var aGlobal = new String('Hello');
+ function someVarLength(str){
+ length = str.length;
+ console.log(length);
+ }
+ somVarLength(aGlobal);

\ No newline at end of file diff --git a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/D4.json b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/D4.json new file mode 100644 index 000000000..18149eaee --- /dev/null +++ b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/D4.json @@ -0,0 +1,13 @@ +{ + "title": "Avoid using global variables", + "type": "CODE_SMELL", + "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "5min" + }, + "tags": [ + "eco-conception" + ], + "defaultSeverity": "Minor" +} \ No newline at end of file diff --git a/src/php-plugin/src/test/java/fr/cnumr/php/MyPhpRulesTest.java b/src/php-plugin/src/test/java/fr/cnumr/php/MyPhpRulesTest.java index eb6862ad9..4fb8302af 100644 --- a/src/php-plugin/src/test/java/fr/cnumr/php/MyPhpRulesTest.java +++ b/src/php-plugin/src/test/java/fr/cnumr/php/MyPhpRulesTest.java @@ -7,7 +7,7 @@ public class MyPhpRulesTest { - private int NumberOfRuleInRepository = 6; + private int NumberOfRuleInRepository = 7; @Test public void rules() { diff --git a/src/php-plugin/src/test/java/fr/cnumr/php/checks/AvoidUsingGlobalVariablesCheckTest.java b/src/php-plugin/src/test/java/fr/cnumr/php/checks/AvoidUsingGlobalVariablesCheckTest.java new file mode 100644 index 000000000..e2156bb20 --- /dev/null +++ b/src/php-plugin/src/test/java/fr/cnumr/php/checks/AvoidUsingGlobalVariablesCheckTest.java @@ -0,0 +1,38 @@ +/* + * SonarQube PHP Custom Rules Example + * Copyright (C) 2016-2016 SonarSource SA + * mailto:contact 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 fr.cnumr.php.checks; + +import org.junit.Test; +import org.sonar.plugins.php.api.tests.PHPCheckTest; +import org.sonar.plugins.php.api.tests.PhpTestFile; + +import java.io.File; + +/** + * Test class to test the check implementation. + */ +public class AvoidUsingGlobalVariablesCheckTest { + + @Test + public void test() throws Exception { + PHPCheckTest.check(new AvoidUsingGlobalVariablesCheck(), new PhpTestFile(new File("src/test/resources/checks/AvoidUsingGlobalVariablesCheck.php"))); + } + +} diff --git a/src/php-plugin/src/test/resources/checks/AvoidUsingGlobalVariablesCheck.php b/src/php-plugin/src/test/resources/checks/AvoidUsingGlobalVariablesCheck.php new file mode 100644 index 000000000..2f5d4eadb --- /dev/null +++ b/src/php-plugin/src/test/resources/checks/AvoidUsingGlobalVariablesCheck.php @@ -0,0 +1,16 @@ + From f087a10ad6c61a98be77f8cd7a3775bdfe784aaf Mon Sep 17 00:00:00 2001 From: OLLIVIER Elodie Date: Thu, 2 Jun 2022 10:33:23 +0200 Subject: [PATCH 007/119] D4-Java --- src/java-plugin/pom.xml | 6 +++ .../main/java/fr/cnumr/java/RulesList.java | 9 ++-- .../AvoidUsingGlobalVariablesCheck.java | 48 +++++++++++++++++++ .../fr/cnumr/l10n/java/rules/java/D4.html | 19 ++++++++ .../fr/cnumr/l10n/java/rules/java/D4.json | 13 +++++ .../files/AvoidUsingGlobalVariablesCheck.java | 20 ++++++++ .../java/MyJavaFileCheckRegistrarTest.java | 3 +- ...oidUsingGlobalVariablesCheckCheckTest.java | 16 +++++++ 8 files changed, 129 insertions(+), 5 deletions(-) create mode 100644 src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidUsingGlobalVariablesCheck.java create mode 100644 src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/D4.html create mode 100644 src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/D4.json create mode 100644 src/java-plugin/src/test/files/AvoidUsingGlobalVariablesCheck.java create mode 100644 src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidUsingGlobalVariablesCheckCheckTest.java diff --git a/src/java-plugin/pom.xml b/src/java-plugin/pom.xml index b391b0899..da9d9f83e 100644 --- a/src/java-plugin/pom.xml +++ b/src/java-plugin/pom.xml @@ -59,6 +59,12 @@ org.assertj assertj-core + + com.google.guava + guava + 31.0.1-jre + compile + diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java b/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java index 7bcd53578..12654edcb 100644 --- a/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java +++ b/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java @@ -19,14 +19,14 @@ */ package fr.cnumr.java; +import fr.cnumr.java.checks.*; +import org.sonar.plugins.java.api.JavaCheck; + import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; -import fr.cnumr.java.checks.*; -import org.sonar.plugins.java.api.JavaCheck; - public final class RulesList { private RulesList() { @@ -46,7 +46,8 @@ public static List> getJavaChecks() { AvoidSQLRequestInLoop.class, AvoidFullSQLRequest.class, UseCorrectForLoop.class, - UnnecessarilyAssignValuesToVariables.class + UnnecessarilyAssignValuesToVariables.class, + AvoidUsingGlobalVariablesCheck.class )); } diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidUsingGlobalVariablesCheck.java b/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidUsingGlobalVariablesCheck.java new file mode 100644 index 000000000..884f1456e --- /dev/null +++ b/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidUsingGlobalVariablesCheck.java @@ -0,0 +1,48 @@ +package fr.cnumr.java.checks; + +import com.google.common.collect.ImmutableList; +import org.sonar.check.Priority; +import org.sonar.check.Rule; +import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; +import org.sonar.plugins.java.api.tree.Tree; +import org.sonar.plugins.java.api.tree.Tree.Kind; +import org.sonar.plugins.java.api.tree.VariableTree; + +import java.util.List; +import java.util.regex.Pattern; + +@Rule( + key = "D4", + name = "Developpement", + description = "

Prefer local variables to globals

", + priority = Priority.MINOR, + tags = {"bug"}) +public class AvoidUsingGlobalVariablesCheck extends IssuableSubscriptionVisitor { + + public static final String KEY = "PreferLocalVariablesToGlobalsCheck"; + private static final String ERROR_MESSAGE = "Avoid using global variables"; + public static final String GLOBALS_PATTERN = "^.*(static).*$"; + private Pattern pattern; + + @Override + public List nodesToVisit() { + return ImmutableList.of(Kind.STATIC_INITIALIZER, Kind.VARIABLE, Kind.METHOD); + } + public void visitNode(Tree tree) { + pattern = Pattern.compile(GLOBALS_PATTERN, Pattern.CASE_INSENSITIVE); + + if(tree.is(Kind.STATIC_INITIALIZER)){ + reportIssue(tree, String.format(ERROR_MESSAGE, tree)); + } + if(tree.is(Kind.VARIABLE)){ + VariableTree variableTree = (VariableTree) tree; + int modifiersSize = ((VariableTree) tree).modifiers().modifiers().size(); + for(int i = 0; i < modifiersSize;i++){ + String modifier = ((VariableTree) tree).modifiers().modifiers().get(i).modifier().toString(); + if (pattern.matcher(modifier).matches()) { + reportIssue(tree, String.format(ERROR_MESSAGE, modifier)); + } + } + } + } +} \ No newline at end of file diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/D4.html b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/D4.html new file mode 100644 index 000000000..aa33197ba --- /dev/null +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/D4.html @@ -0,0 +1,19 @@ +

+ Prefer local variables as parameters +

+

A l'appel d'une variable globale, le moteur d'interprétation doit vérifier son existence dans tous les scopes, qu'elle dispose d'une valeur, etc. Passer les variables globales en argument de routines les rend locales dans la fonction, permettant ainsi d'économiser du temps de calcul (cycles CPU). +

+

exemple:
+ var aGlobal = new String('Hello');
+ function globalLength(){
+ length = aGlobal.length;
+ console.log(length);
+ }
+ globalLength();
+
+ var aGlobal = new String('Hello');
+ function someVarLength(str){
+ length = str.length;
+ console.log(length);
+ }
+ somVarLength(aGlobal);

\ No newline at end of file diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/D4.json b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/D4.json new file mode 100644 index 000000000..18149eaee --- /dev/null +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/D4.json @@ -0,0 +1,13 @@ +{ + "title": "Avoid using global variables", + "type": "CODE_SMELL", + "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "5min" + }, + "tags": [ + "eco-conception" + ], + "defaultSeverity": "Minor" +} \ No newline at end of file diff --git a/src/java-plugin/src/test/files/AvoidUsingGlobalVariablesCheck.java b/src/java-plugin/src/test/files/AvoidUsingGlobalVariablesCheck.java new file mode 100644 index 000000000..344e237b4 --- /dev/null +++ b/src/java-plugin/src/test/files/AvoidUsingGlobalVariablesCheck.java @@ -0,0 +1,20 @@ +public class Openclass { + public static double price = 15.24; // Noncompliant + public static long pages = 1053; // Noncompliant + + public static void main(String[] args) { + double newPrice = Openclass.price; + long newPages = Openclass.pages; + System.out.println(newPrice); + System.out.println(newPages); + static long years = 3000; // Noncompliant + } + static{ // Noncompliant + int a = 4; + } + + public void printingA() { + System.out.println(a); + } + +} \ No newline at end of file diff --git a/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java b/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java index bbc12316c..a659b9c6b 100644 --- a/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java +++ b/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java @@ -21,6 +21,7 @@ import org.junit.jupiter.api.Test; import org.sonar.plugins.java.api.CheckRegistrar; + import static org.assertj.core.api.Assertions.assertThat; class MyJavaFileCheckRegistrarTest { @@ -32,7 +33,7 @@ void checkNumberRules() { MyJavaFileCheckRegistrar registrar = new MyJavaFileCheckRegistrar(); registrar.register(context); - assertThat(context.checkClasses()).hasSize(6); + assertThat(context.checkClasses()).hasSize(7); assertThat(context.testCheckClasses()).isEmpty(); } diff --git a/src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidUsingGlobalVariablesCheckCheckTest.java b/src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidUsingGlobalVariablesCheckCheckTest.java new file mode 100644 index 000000000..6447ede61 --- /dev/null +++ b/src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidUsingGlobalVariablesCheckCheckTest.java @@ -0,0 +1,16 @@ +package fr.cnumr.java.checks; + +import org.junit.jupiter.api.Test; +import org.sonar.java.checks.verifier.JavaCheckVerifier; + +class AvoidUsingGlobalVariablesCheckCheckTest { + + @Test + void test() { + JavaCheckVerifier.newVerifier() + .onFile("src/test/files/AvoidUsingGlobalVariablesCheck.java") + .withCheck(new AvoidUsingGlobalVariablesCheck()) + .verifyIssues(); + } + +} \ No newline at end of file From f8bbde51627d2def91785976a4673210e923184a Mon Sep 17 00:00:00 2001 From: Ahmed Bahri Date: Thu, 2 Jun 2022 13:53:03 +0200 Subject: [PATCH 008/119] ahmed partie HTML/JSON --- .../fr/cnumr/l10n/python/rules/python/64.html | 36 +++++++++++++++++++ .../fr/cnumr/l10n/python/rules/python/64.json | 13 +++++++ 2 files changed, 49 insertions(+) create mode 100644 sonarqube-plugin-greenit/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/64.html create mode 100644 sonarqube-plugin-greenit/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/64.json diff --git a/sonarqube-plugin-greenit/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/64.html b/sonarqube-plugin-greenit/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/64.html new file mode 100644 index 000000000..6a406ffaa --- /dev/null +++ b/sonarqube-plugin-greenit/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/64.html @@ -0,0 +1,36 @@ +

Do not execute an SQL request in a loop

+

Noncompliant Code Example

+
+
+    def foo():
+        ...
+        baseQuery= "SELECT name FROM users where id = "
+        for i in range(0,20):
+            query=query + str(i)
+            cursor.execute(query) #Noncompliant
+            for row in cursor:
+                print(row)
+        ...
+        cursor.close()
+
+
+

Compliant Solution

+
+
+    def  foo() {
+        ...
+        query = "SELECT name FROM users where id in (0 "
+        for i in range(0,20):
+            query = query +","+str(i)
+        query+=")"
+        cursor.execute(query) #compliant
+
+        # iterate through the  resultset
+        for row in cursor:
+            print(row)
+
+        cursor.close();
+        ...
+   }
+
+
diff --git a/sonarqube-plugin-greenit/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/64.json b/sonarqube-plugin-greenit/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/64.json new file mode 100644 index 000000000..73743a5a5 --- /dev/null +++ b/sonarqube-plugin-greenit/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/64.json @@ -0,0 +1,13 @@ +{ + "title": "Avoid SQL request in loop", + "type": "CODE_SMELL", + "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "10min" + }, + "tags": [ + "eco-conception" + ], + "defaultSeverity": "Minor" +} \ No newline at end of file From aad8a4631085d366bf7a7aac6c1345ace2438d90 Mon Sep 17 00:00:00 2001 From: Lsdla Date: Thu, 2 Jun 2022 14:45:35 +0200 Subject: [PATCH 009/119] first commit- fix bug php plugin --- src/docker-compose.yml | 6 +++--- src/pom.xml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/docker-compose.yml b/src/docker-compose.yml index 541ba112d..5bfe2b9fb 100644 --- a/src/docker-compose.yml +++ b/src/docker-compose.yml @@ -17,9 +17,9 @@ services: - type: bind source: ./java-plugin/target/ecocode-java-plugin-1.0.0-SNAPSHOT.jar target: /opt/sonarqube/extensions/plugins/ecocode-java-plugin-1.0.0-SNAPSHOT.jar - - type: bind - source: ./php-plugin/target/ecocode-php-plugin-1.0.0-SNAPSHOT.jar - target: /opt/sonarqube/extensions/plugins/ecocode-php-plugin-1.0.0-SNAPSHOT.jar + #- type: bind + # source: ./php-plugin/target/ecocode-php-plugin-1.0.0-SNAPSHOT.jar + # target: /opt/sonarqube/extensions/plugins/ecocode-php-plugin-1.0.0-SNAPSHOT.jar - type: bind source: ./python-plugin/target/ecocode-python-plugin-1.0.0-SNAPSHOT.jar target: /opt/sonarqube/extensions/plugins/ecocode-python-plugin-1.0.0-SNAPSHOT.jar diff --git a/src/pom.xml b/src/pom.xml index a622db208..a11f63101 100644 --- a/src/pom.xml +++ b/src/pom.xml @@ -28,7 +28,7 @@ java-plugin - php-plugin + python-plugin codenarc-converter android-plugin From c1336678b781a6076a7d38537cf5a4c4b469a767 Mon Sep 17 00:00:00 2001 From: ahmedcove1 Date: Thu, 2 Jun 2022 14:46:38 +0200 Subject: [PATCH 010/119] =?UTF-8?q?4=20fichiers=20ajout=C3=A9=20html/json/?= =?UTF-8?q?python/java-test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/.gitignore | 8 +++ .idea/ecoCode.iml | 9 ++++ .idea/modules.xml | 8 +++ .idea/vcs.xml | 6 +++ .../fr/cnumr/l10n/python/rules/python/64.json | 1 + .../AvoidSQLRequestInLoopCheckTest.java | 12 +++++ .../checks/AvoidSQLRequestInLoopCheck.py | 51 +++++++++++++++++++ 7 files changed, 95 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 .idea/ecoCode.iml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 sonarqube-plugin-greenit/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidSQLRequestInLoopCheckTest.java create mode 100644 sonarqube-plugin-greenit/python-plugin/src/test/resources/checks/AvoidSQLRequestInLoopCheck.py diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 000000000..13566b81b --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/ecoCode.iml b/.idea/ecoCode.iml new file mode 100644 index 000000000..d6ebd4805 --- /dev/null +++ b/.idea/ecoCode.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 000000000..648097b9c --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 000000000..35eb1ddfb --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/sonarqube-plugin-greenit/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/64.json b/sonarqube-plugin-greenit/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/64.json index 73743a5a5..7f1dc865f 100644 --- a/sonarqube-plugin-greenit/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/64.json +++ b/sonarqube-plugin-greenit/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/64.json @@ -1,6 +1,7 @@ { "title": "Avoid SQL request in loop", "type": "CODE_SMELL", + "status": "ready", "remediation": { "func": "Constant\/Issue", diff --git a/sonarqube-plugin-greenit/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidSQLRequestInLoopCheckTest.java b/sonarqube-plugin-greenit/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidSQLRequestInLoopCheckTest.java new file mode 100644 index 000000000..dc5a47206 --- /dev/null +++ b/sonarqube-plugin-greenit/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidSQLRequestInLoopCheckTest.java @@ -0,0 +1,12 @@ +package fr.cnumr.python.checks; + +import org.junit.Test; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class AvoidSQLRequestInLoopCheckTest { + + @Test + public void test() { + PythonCheckVerifier.verify("src/test/resources/checks/AvoidSQLRequestInLoopCheck.py", new AvoidSQLRequestInLoopCheckTest()); + } +} \ No newline at end of file diff --git a/sonarqube-plugin-greenit/python-plugin/src/test/resources/checks/AvoidSQLRequestInLoopCheck.py b/sonarqube-plugin-greenit/python-plugin/src/test/resources/checks/AvoidSQLRequestInLoopCheck.py new file mode 100644 index 000000000..752973303 --- /dev/null +++ b/sonarqube-plugin-greenit/python-plugin/src/test/resources/checks/AvoidSQLRequestInLoopCheck.py @@ -0,0 +1,51 @@ +import mysql.connector +from mysql.connector.cursor import MySQLCursor + + +class AvoidSQLRequestInLoopCheck: + def testWithNoLoop(self): + try : + db = mysql.connector.connect(option_files='my.conf', use_pure=True) + cursor=db.cursor() + query = "SELECT * FROM users" + cursor.execute(query) + with row in cursor: + print(row.id) + cursor.close() + db.close() + except : + print("Got an exception") + db.close() + + def testWithForLoop(): + try: + db = mysql.connector.connect(option_files='my.conf', use_pure=True) + query = "SELECT * FROM users where id = " + for i in range(0,20): + cursor=db.cursor() + query+=str(i) + cursor.execute(query) #Noncompliant + with row in cursor: + print(row.name) + cursor.close() + except : + print("Got an exception") + db.close() + + def testWithWhileLoop(): + try: + db = mysql.connector.connect(option_files='my.conf', use_pure=True) + query = "SELECT * FROM users where id = " + i = 0 + while i<20: + + cursor=db.cursor() + query+=str(i) + cursor.execute(query) #Noncompliant + with row in cursor: + print(row.name) + cursor.close() + i+=1 + except : + print("Got an exception") + db.close() From ca9f66fe767e72be5cfdbda218d1fc117a379c71 Mon Sep 17 00:00:00 2001 From: ahmedcove1 Date: Thu, 2 Jun 2022 15:31:14 +0200 Subject: [PATCH 011/119] ajout partie executemany --- .idea/inspectionProfiles/Project_Default.xml | 6 ++++++ .idea/misc.xml | 4 ++++ .../fr/cnumr/l10n/python/rules/python/64.html | 12 ++++++++++++ .../checks/AvoidSQLRequestInLoopCheck.py | 15 ++++++++++++++- 4 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 .idea/inspectionProfiles/Project_Default.xml create mode 100644 .idea/misc.xml diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 000000000..ac21435ff --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 000000000..412cda9dd --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/sonarqube-plugin-greenit/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/64.html b/sonarqube-plugin-greenit/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/64.html index 6a406ffaa..d40de7588 100644 --- a/sonarqube-plugin-greenit/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/64.html +++ b/sonarqube-plugin-greenit/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/64.html @@ -12,8 +12,20 @@

Noncompliant Code Example

print(row) ... cursor.close() +----------------------------------------------------------- + def foo(): + ... + baseQuery= "SELECT name FROM users where id = " + data = [ i for i in range(0,20) ] + cursor.executemany(baseQuery,data) + for row in cursor: + print(row) + ... + cursor.close() + +

Compliant Solution

 
diff --git a/sonarqube-plugin-greenit/python-plugin/src/test/resources/checks/AvoidSQLRequestInLoopCheck.py b/sonarqube-plugin-greenit/python-plugin/src/test/resources/checks/AvoidSQLRequestInLoopCheck.py
index 752973303..b3233e59d 100644
--- a/sonarqube-plugin-greenit/python-plugin/src/test/resources/checks/AvoidSQLRequestInLoopCheck.py
+++ b/sonarqube-plugin-greenit/python-plugin/src/test/resources/checks/AvoidSQLRequestInLoopCheck.py
@@ -1,5 +1,4 @@
 import mysql.connector
-from mysql.connector.cursor import MySQLCursor
 
 
 class AvoidSQLRequestInLoopCheck:
@@ -49,3 +48,17 @@ def testWithWhileLoop():
           except :
               print("Got an exception")
               db.close()
+
+    def testWithExecuteMany():
+        try:
+            db =db = mysql.connector.connect(option_files='my.conf', use_pure=True)
+            query = "SELECT * FROM users where id = %d"
+            cursor=db.cursor()
+            data = [1,2,3,4,5,6]
+            cursor.executemany(query,data)
+            with row in cursor:
+                print(row.name)
+            cursor.close()
+        except:
+            print("Got an exception")
+            db.close()
\ No newline at end of file

From 18ae0fc20a308bc67b255140ce5987f3fd5e5fa3 Mon Sep 17 00:00:00 2001
From: ahmedcove1 
Date: Thu, 2 Jun 2022 15:33:42 +0200
Subject: [PATCH 012/119] modification code de test.py

---
 .../src/test/resources/checks/AvoidSQLRequestInLoopCheck.py     | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sonarqube-plugin-greenit/python-plugin/src/test/resources/checks/AvoidSQLRequestInLoopCheck.py b/sonarqube-plugin-greenit/python-plugin/src/test/resources/checks/AvoidSQLRequestInLoopCheck.py
index b3233e59d..1b0412875 100644
--- a/sonarqube-plugin-greenit/python-plugin/src/test/resources/checks/AvoidSQLRequestInLoopCheck.py
+++ b/sonarqube-plugin-greenit/python-plugin/src/test/resources/checks/AvoidSQLRequestInLoopCheck.py
@@ -54,7 +54,7 @@ def testWithExecuteMany():
             db =db = mysql.connector.connect(option_files='my.conf', use_pure=True)
             query = "SELECT * FROM users where id = %d"
             cursor=db.cursor()
-            data = [1,2,3,4,5,6]
+            data = [i for i in range(20)]
             cursor.executemany(query,data)
             with row in cursor:
                 print(row.name)

From faa01b7e5af25c92efab7ae5563bef7cf02834d6 Mon Sep 17 00:00:00 2001
From: OLLIVIER Elodie 
Date: Thu, 2 Jun 2022 16:32:28 +0200
Subject: [PATCH 013/119] D1-PHP (S64 fourni NOK)

---
 .../main/java/fr/cnumr/php/MyPhpRules.java    |  2 +-
 ...nallyCheck_NOK_failsAllTryStatements.java} |  4 +-
 .../AvoidUsingFinallyInTryCatchCheck.java     | 53 +++++++++++++++++++
 .../fr/cnumr/l10n/php/rules/custom/D1.html    |  2 +
 .../fr/cnumr/l10n/php/rules/custom/D1.json    | 13 +++++
 .../java/fr/cnumr/php/MyPhpRulesTest.java     |  2 +-
 ...allyCheckNOKfailsAllTryStatementsTest.java | 16 ++++++
 .../checks/AvoidTryCatchFinallyCheckTest.java | 16 ------
 .../AvoidUsingFinallyInTryCatchCheckTest.java | 38 +++++++++++++
 .../AvoidUsingFinallyInTryCatchCheck.php      | 22 ++++++++
 ...inallyCheck_NOK_FailsAllTryStatements.php} |  7 +++
 11 files changed, 155 insertions(+), 20 deletions(-)
 rename src/php-plugin/src/main/java/fr/cnumr/php/checks/{AvoidTryCatchFinallyCheck.java => AvoidTryCatchFinallyCheck_NOK_failsAllTryStatements.java} (79%)
 create mode 100644 src/php-plugin/src/main/java/fr/cnumr/php/checks/AvoidUsingFinallyInTryCatchCheck.java
 create mode 100644 src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/D1.html
 create mode 100644 src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/D1.json
 create mode 100644 src/php-plugin/src/test/java/fr/cnumr/php/checks/AvoidTryCatchFinallyCheckNOKfailsAllTryStatementsTest.java
 delete mode 100644 src/php-plugin/src/test/java/fr/cnumr/php/checks/AvoidTryCatchFinallyCheckTest.java
 create mode 100644 src/php-plugin/src/test/java/fr/cnumr/php/checks/AvoidUsingFinallyInTryCatchCheckTest.java
 create mode 100644 src/php-plugin/src/test/resources/checks/AvoidUsingFinallyInTryCatchCheck.php
 rename src/php-plugin/src/test/resources/checks/{avoidTryCatchFinallyCheck.php => avoidTryCatchFinallyCheck_NOK_FailsAllTryStatements.php} (81%)

diff --git a/src/php-plugin/src/main/java/fr/cnumr/php/MyPhpRules.java b/src/php-plugin/src/main/java/fr/cnumr/php/MyPhpRules.java
index 29393a555..da8ff66cc 100644
--- a/src/php-plugin/src/main/java/fr/cnumr/php/MyPhpRules.java
+++ b/src/php-plugin/src/main/java/fr/cnumr/php/MyPhpRules.java
@@ -53,7 +53,7 @@ public String repositoryKey() {
    */
   @Override
   public ImmutableList checkClasses() {
-    return ImmutableList.of(IncrementCheck.class, AvoidTryCatchFinallyCheck.class, AvoidDoubleQuoteCheck.class,
+    return ImmutableList.of(AvoidUsingFinallyInTryCatchCheck.class, IncrementCheck.class, AvoidTryCatchFinallyCheck_NOK_failsAllTryStatements.class, AvoidDoubleQuoteCheck.class,
             AvoidFullSQLRequestCheck.class, AvoidSQLRequestInLoopCheck.class, NoFunctionCallWhenDeclaringForLoop.class);
   }
 
diff --git a/src/php-plugin/src/main/java/fr/cnumr/php/checks/AvoidTryCatchFinallyCheck.java b/src/php-plugin/src/main/java/fr/cnumr/php/checks/AvoidTryCatchFinallyCheck_NOK_failsAllTryStatements.java
similarity index 79%
rename from src/php-plugin/src/main/java/fr/cnumr/php/checks/AvoidTryCatchFinallyCheck.java
rename to src/php-plugin/src/main/java/fr/cnumr/php/checks/AvoidTryCatchFinallyCheck_NOK_failsAllTryStatements.java
index 9fa6b6d05..739206d6c 100644
--- a/src/php-plugin/src/main/java/fr/cnumr/php/checks/AvoidTryCatchFinallyCheck.java
+++ b/src/php-plugin/src/main/java/fr/cnumr/php/checks/AvoidTryCatchFinallyCheck_NOK_failsAllTryStatements.java
@@ -11,10 +11,10 @@
 @Rule(
         key = "S34",
         name = "Developpement",
-        description = AvoidTryCatchFinallyCheck.ERROR_MESSAGE,
+        description = AvoidTryCatchFinallyCheck_NOK_failsAllTryStatements.ERROR_MESSAGE,
         priority = Priority.MINOR,
         tags = {"bug"})
-public class AvoidTryCatchFinallyCheck extends PHPSubscriptionCheck {
+public class AvoidTryCatchFinallyCheck_NOK_failsAllTryStatements extends PHPSubscriptionCheck {
 
     public static final String ERROR_MESSAGE = "Avoid using try-catch-finally";
 
diff --git a/src/php-plugin/src/main/java/fr/cnumr/php/checks/AvoidUsingFinallyInTryCatchCheck.java b/src/php-plugin/src/main/java/fr/cnumr/php/checks/AvoidUsingFinallyInTryCatchCheck.java
new file mode 100644
index 000000000..fdcc15ab0
--- /dev/null
+++ b/src/php-plugin/src/main/java/fr/cnumr/php/checks/AvoidUsingFinallyInTryCatchCheck.java
@@ -0,0 +1,53 @@
+/*
+ * SonarQube PHP Custom Rules Example
+ * Copyright (C) 2016-2016 SonarSource SA
+ * mailto:contact 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 fr.cnumr.php.checks;
+
+
+import org.sonar.check.Priority;
+import org.sonar.check.Rule;
+import org.sonar.plugins.php.api.tree.statement.TryStatementTree;
+import org.sonar.plugins.php.api.visitors.PHPVisitorCheck;
+
+@Rule(
+        key = "D1",
+        priority = Priority.MAJOR,
+        name = "Avoid using finally in try/catch",
+        tags = {"bug"})
+public class AvoidUsingFinallyInTryCatchCheck extends PHPVisitorCheck  {
+
+    private static final String ERROR_MESSAGE = "Avoid using finally in try/catch";
+
+
+    @Override
+    public void visitTryStatement(TryStatementTree tree) {
+        if(tree.finallyToken() != null){
+            StringBuilder sb =  new StringBuilder();
+            sb.append(tree.finallyToken().toString());
+            sb.append(tree.finallyBlock().toString());
+            context().newIssue(this, tree.finallyToken(), String.format(ERROR_MESSAGE, sb));
+
+        }
+    }
+
+
+
+
+}
+
diff --git a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/D1.html b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/D1.html
new file mode 100644
index 000000000..dc1b235b5
--- /dev/null
+++ b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/D1.html
@@ -0,0 +1,2 @@
+

Avoid using try-catch-finally statement

+

Lorsqu'une exception est levée, une variable (l'exception elle-même) est créée dans le bloc catch et détruite à la fin du bloc. La création de cette variable et sa destruction consomment inutilement des cycle CPU et de la mémoire vive. Il faut mieux lui préférer autant que possible un test logique. diff --git a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/D1.json b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/D1.json new file mode 100644 index 000000000..72a37f621 --- /dev/null +++ b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/D1.json @@ -0,0 +1,13 @@ +{ + "title": "Avoid using try-catch-finally statement", + "type": "CODE_SMELL", + "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "5min" + }, + "tags": [ + "eco-conception" + ], + "defaultSeverity": "Minor" +} \ No newline at end of file diff --git a/src/php-plugin/src/test/java/fr/cnumr/php/MyPhpRulesTest.java b/src/php-plugin/src/test/java/fr/cnumr/php/MyPhpRulesTest.java index eb6862ad9..4fb8302af 100644 --- a/src/php-plugin/src/test/java/fr/cnumr/php/MyPhpRulesTest.java +++ b/src/php-plugin/src/test/java/fr/cnumr/php/MyPhpRulesTest.java @@ -7,7 +7,7 @@ public class MyPhpRulesTest { - private int NumberOfRuleInRepository = 6; + private int NumberOfRuleInRepository = 7; @Test public void rules() { diff --git a/src/php-plugin/src/test/java/fr/cnumr/php/checks/AvoidTryCatchFinallyCheckNOKfailsAllTryStatementsTest.java b/src/php-plugin/src/test/java/fr/cnumr/php/checks/AvoidTryCatchFinallyCheckNOKfailsAllTryStatementsTest.java new file mode 100644 index 000000000..e270951d2 --- /dev/null +++ b/src/php-plugin/src/test/java/fr/cnumr/php/checks/AvoidTryCatchFinallyCheckNOKfailsAllTryStatementsTest.java @@ -0,0 +1,16 @@ +package fr.cnumr.php.checks; + +import org.junit.Test; +import org.sonar.plugins.php.api.tests.PHPCheckTest; +import org.sonar.plugins.php.api.tests.PhpTestFile; + +import java.io.File; + +public class AvoidTryCatchFinallyCheckNOKfailsAllTryStatementsTest { + + @Test + public void test() throws Exception { + PHPCheckTest.check(new AvoidTryCatchFinallyCheck_NOK_failsAllTryStatements(), new PhpTestFile(new File("src/test/resources/checks/avoidTryCatchFinallyCheck_NOK_FailsAllTryStatements.php"))); + } + +} diff --git a/src/php-plugin/src/test/java/fr/cnumr/php/checks/AvoidTryCatchFinallyCheckTest.java b/src/php-plugin/src/test/java/fr/cnumr/php/checks/AvoidTryCatchFinallyCheckTest.java deleted file mode 100644 index 4b4515983..000000000 --- a/src/php-plugin/src/test/java/fr/cnumr/php/checks/AvoidTryCatchFinallyCheckTest.java +++ /dev/null @@ -1,16 +0,0 @@ -package fr.cnumr.php.checks; - -import org.junit.Test; -import org.sonar.plugins.php.api.tests.PHPCheckTest; -import org.sonar.plugins.php.api.tests.PhpTestFile; - -import java.io.File; - -public class AvoidTryCatchFinallyCheckTest{ - - @Test - public void test() throws Exception { - PHPCheckTest.check(new AvoidTryCatchFinallyCheck(), new PhpTestFile(new File("src/test/resources/checks/avoidTryCatchFinallyCheck.php"))); - } - -} diff --git a/src/php-plugin/src/test/java/fr/cnumr/php/checks/AvoidUsingFinallyInTryCatchCheckTest.java b/src/php-plugin/src/test/java/fr/cnumr/php/checks/AvoidUsingFinallyInTryCatchCheckTest.java new file mode 100644 index 000000000..4f619779d --- /dev/null +++ b/src/php-plugin/src/test/java/fr/cnumr/php/checks/AvoidUsingFinallyInTryCatchCheckTest.java @@ -0,0 +1,38 @@ +/* + * SonarQube PHP Custom Rules Example + * Copyright (C) 2016-2016 SonarSource SA + * mailto:contact 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 fr.cnumr.php.checks; + +import org.junit.Test; +import org.sonar.plugins.php.api.tests.PHPCheckVerifier; +import org.sonar.plugins.php.api.tests.PhpTestFile; + +import java.io.File; + +/** + * Test class to test the check implementation. + */ +public class AvoidUsingFinallyInTryCatchCheckTest { + + @Test + public void test(){ + PHPCheckVerifier.verify(new PhpTestFile(new File("src/test/resources/checks/AvoidUsingFinallyInTryCatchCheck.php")),new AvoidUsingFinallyInTryCatchCheck()); + } + +} diff --git a/src/php-plugin/src/test/resources/checks/AvoidUsingFinallyInTryCatchCheck.php b/src/php-plugin/src/test/resources/checks/AvoidUsingFinallyInTryCatchCheck.php new file mode 100644 index 000000000..a62e2078c --- /dev/null +++ b/src/php-plugin/src/test/resources/checks/AvoidUsingFinallyInTryCatchCheck.php @@ -0,0 +1,22 @@ +getMessage(), "\n"; +} finally { //Noncompliant {{Avoid using finally in try/catch}} + echo "Première fin.\n"; +} + +try { + echo inverse(2) . "\n"; +} catch (Exception $e) { + echo 'Exception reçue : ', $e->getMessage(), "\n"; +} + diff --git a/src/php-plugin/src/test/resources/checks/avoidTryCatchFinallyCheck.php b/src/php-plugin/src/test/resources/checks/avoidTryCatchFinallyCheck_NOK_FailsAllTryStatements.php similarity index 81% rename from src/php-plugin/src/test/resources/checks/avoidTryCatchFinallyCheck.php rename to src/php-plugin/src/test/resources/checks/avoidTryCatchFinallyCheck_NOK_FailsAllTryStatements.php index b604ae74e..a243fc054 100644 --- a/src/php-plugin/src/test/resources/checks/avoidTryCatchFinallyCheck.php +++ b/src/php-plugin/src/test/resources/checks/avoidTryCatchFinallyCheck_NOK_FailsAllTryStatements.php @@ -26,4 +26,11 @@ function test() { echo $e->getMessage()." finally \n"; throw new \Exception("Bye"); } +//FAILS with this RULE +/*try { + throw new \Exception("Hello"); +} catch(\Exception $e) { + echo $e->getMessage()." catch in\n"; + throw $e; +}*/ ?> From c813306f0d73dfd3bde51eaf6055c3d84ccd68b5 Mon Sep 17 00:00:00 2001 From: Jules Delecour <72793427+jules-delecour-dav@users.noreply.github.com> Date: Thu, 2 Jun 2022 17:18:56 +0200 Subject: [PATCH 014/119] Sonarcloud (#100) * Update build.yml * Update build.yml * Update build.yml * Update build.yml * Update build.yml * Update build.yml * Update pom.xml * Update pom.xml * Update build.yml * Update build.yml * Update build.yml * Update build.yml * Update build.yml * Update pom.xml * Update build.yml --- .github/workflows/build.yml | 16 ++++++++++++++-- src/pom.xml | 3 ++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bd1ae7cab..ceaaf4d43 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,7 +3,6 @@ on: push: branches: - master - - sonarcloud pull_request: types: [opened, synchronize, reopened] jobs: @@ -30,8 +29,21 @@ jobs: path: ~/.m2 key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} restore-keys: ${{ runner.os }}-m2 + - name: Setup Gradle + uses: gradle/gradle-build-action@v2 + - name: Execute Gradle build CodeNarc + working-directory: ./src/codenarc-converter/CodeNarc + run: | + chmod +x gradlew + ./gradlew build -x test + - name: Execute Maven build CodeNarc + working-directory: ./src/codenarc-converter + run: | + mvn initialize + mvn clean package - name: Build and analyze + working-directory: ./src env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - run: mvn -f ./src/pom.xml -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=cnumr_ecoCode -Dsonar.sources=./src + run: mvn -e -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=cnumr_ecoCode -Dsonar.exclusions=**/src/codenarc-converter/**,**/*.groovy,**/src/android-plugin/src/test/**,**/*.dummy diff --git a/src/pom.xml b/src/pom.xml index a622db208..112dff9f4 100644 --- a/src/pom.xml +++ b/src/pom.xml @@ -76,7 +76,7 @@ UTF-8 1.8 1.8 - cnumr + cnumr-1 https://sonarcloud.io @@ -180,4 +180,5 @@ + From ead2cd1166bdfb9a876c3c628c9511abbd9c1e7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Le=20Goa=C3=ABr?= Date: Thu, 2 Jun 2022 17:50:59 +0200 Subject: [PATCH 015/119] fix already implemented rules --- hackathon/work-packages.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/hackathon/work-packages.md b/hackathon/work-packages.md index 557350a1e..7298b7842 100644 --- a/hackathon/work-packages.md +++ b/hackathon/work-packages.md @@ -68,10 +68,8 @@ The set of rules comes from the detailed [Energy Smells catalog](https://olegoae | ESOB009 | Day Night Mode | File System, Xml | | ESOB014 | High Frame Rate | Java | | EBAT001 | Service@Boot-time | Java, Xml | -| EREL003 | Supported Version Range | Xml, Gradle | | EREL004 | Same dependencies | Gradle | | EREL005 | Duplicate dependencies | Gradle | -| EREL006 | Fat app | Gradle | | EREL007 | Clear cache | Java | | EREL008 | Concert to WebP | File System | | EREL009 | Shrink Resources | Gradle | From 8de5e94e62550e715979f7a5c155482ec4c6931b Mon Sep 17 00:00:00 2001 From: Cyrille Chopelet Date: Thu, 2 Jun 2022 14:40:19 +0200 Subject: [PATCH 016/119] [CodeNarc] Automate CodeNarc build from Maven's initialize `mvn initialize` will now call the gradle build for CodeNarc, thus reducing the number of necessary steps to start working on the project. The initialize can be run on the root project. The only side-effect is that it will start two jacoco-maven-plugin:prepare-agent. Those don't affect the build, but they could be avoided by changing their execution phase (maybe a phase that would execute it only if tests are run?). .gradle has been added to the root .gitignore (since the command is not run from the same place and results in a .gradle folder that is not ignored), and comments and a new rule have been added. --- .gitignore | 10 +++++++++- src/INSTALL.md | 4 ---- src/codenarc-converter/pom.xml | 19 +++++++++++++++++++ 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 94ad6a98e..b2dc40204 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ +# Markdown README.md.tmp.html +# Maven target/ pom.xml.tag pom.xml.releaseBackup @@ -12,9 +14,15 @@ buildNumber.properties # https://github.com/takari/maven-wrapper#usage-without-binary-jar .mvn/wrapper/maven-wrapper.jar +# Gradle +.gradle/ + # Eclipse m2e generated files # Eclipse Core .project # JDT-specific (Eclipse Java Development Tools) .classpath -**/.settings \ No newline at end of file +.settings/ + +# IntelliJ IDEA settings +.idea/ diff --git a/src/INSTALL.md b/src/INSTALL.md index 6b32024c5..b86dbf64c 100644 --- a/src/INSTALL.md +++ b/src/INSTALL.md @@ -42,11 +42,7 @@ CodeNarc must be built separately. Please see the following steps: Build CodeNarc (Gradle 6.9.2, Java 11), then add this custom-built CodeNarc to Maven dependencies: ```sh -cd codenarc-converter/CodeNarc -./gradlew build -x test -cd .. mvn initialize -cd .. ``` diff --git a/src/codenarc-converter/pom.xml b/src/codenarc-converter/pom.xml index 1cbd28e2f..c6497d448 100644 --- a/src/codenarc-converter/pom.xml +++ b/src/codenarc-converter/pom.xml @@ -125,6 +125,24 @@ exec-maven-plugin 3.0.0 + + + generate-codenarc + initialize + + exec + + + CodeNarc/gradlew + + -p + CodeNarc + build + -x + test + + + run-codenarc-converter generate-test-sources @@ -147,6 +165,7 @@ 2.5.2 + deploy-codenarc-to-local-repo initialize install-file From 8bbd0806962eeea94470ebccb431573fac319d19 Mon Sep 17 00:00:00 2001 From: Lsdla Date: Thu, 2 Jun 2022 19:15:20 +0200 Subject: [PATCH 017/119] add EBOT004 UncachedDataReceptionRule --- .idea/.gitignore | 8 ++ .idea/compiler.xml | 17 +++ .idea/ecoCode.iml | 9 ++ .idea/encodings.xml | 14 ++ .idea/gradle.xml | 18 +++ .idea/jarRepositories.xml | 35 +++++ .idea/misc.xml | 16 +++ .idea/modules.xml | 8 ++ .idea/runConfigurations.xml | 10 ++ .idea/uiDesigner.xml | 124 ++++++++++++++++++ .idea/vcs.xml | 6 + .../java/io/ecocode/java/JavaCheckList.java | 4 +- .../bottleneck/InternetInTheLoopRule.java | 2 +- .../bottleneck/UncachedDataReceptionRule.java | 43 ++++++ .../l10n/java/rules/squid/EBOT004_java.html | 14 ++ .../l10n/java/rules/squid/EBOT004_java.json | 15 +++ .../rules/squid/ecocode_java_profile.json | 5 +- .../UncachedDataReceptionCheck.java | 13 ++ .../ecocode/java/JavaRulesDefinitionTest.java | 6 + .../UncachedDataReceptionRuleTest.java | 14 ++ src/codenarc-converter/CodeNarc/gradlew | 0 21 files changed, 377 insertions(+), 4 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/compiler.xml create mode 100644 .idea/ecoCode.iml create mode 100644 .idea/encodings.xml create mode 100644 .idea/gradle.xml create mode 100644 .idea/jarRepositories.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/runConfigurations.xml create mode 100644 .idea/uiDesigner.xml create mode 100644 .idea/vcs.xml create mode 100644 src/android-plugin/src/main/java/io/ecocode/java/checks/bottleneck/UncachedDataReceptionRule.java create mode 100644 src/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/EBOT004_java.html create mode 100644 src/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/EBOT004_java.json create mode 100644 src/android-plugin/src/test/files/bottleneck/UncachedDataReceptionCheck.java create mode 100644 src/android-plugin/src/test/java/io/ecocode/java/checks/bottleneck/UncachedDataReceptionRuleTest.java mode change 100644 => 100755 src/codenarc-converter/CodeNarc/gradlew diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 000000000..73f69e095 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 000000000..3e0369ed6 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/ecoCode.iml b/.idea/ecoCode.iml new file mode 100644 index 000000000..d6ebd4805 --- /dev/null +++ b/.idea/ecoCode.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 000000000..3485ac0f0 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 000000000..f0822bd42 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 000000000..995f69966 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 000000000..ccc59f084 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 000000000..648097b9c --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 000000000..797acea53 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 000000000..e96534fb2 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 000000000..35eb1ddfb --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/android-plugin/src/main/java/io/ecocode/java/JavaCheckList.java b/src/android-plugin/src/main/java/io/ecocode/java/JavaCheckList.java index d1e2ff247..9eaeacabc 100644 --- a/src/android-plugin/src/main/java/io/ecocode/java/JavaCheckList.java +++ b/src/android-plugin/src/main/java/io/ecocode/java/JavaCheckList.java @@ -22,6 +22,7 @@ import io.ecocode.java.checks.batch.JobCoalesceRule; import io.ecocode.java.checks.batch.SensorCoalesceRule; import io.ecocode.java.checks.bottleneck.InternetInTheLoopRule; +import io.ecocode.java.checks.bottleneck.UncachedDataReceptionRule; import io.ecocode.java.checks.bottleneck.UncompressedDataTransmissionRule; import io.ecocode.java.checks.bottleneck.WifiMulticastLockRule; import io.ecocode.java.checks.idleness.*; @@ -81,7 +82,8 @@ public static List> getJavaChecks() { SensorCoalesceRule.class, JobCoalesceRule.class, SaveModeAwarenessRule.class, - ThriftyGeolocationCriteriaRule.class + ThriftyGeolocationCriteriaRule.class, + UncachedDataReceptionRule.class )); } diff --git a/src/android-plugin/src/main/java/io/ecocode/java/checks/bottleneck/InternetInTheLoopRule.java b/src/android-plugin/src/main/java/io/ecocode/java/checks/bottleneck/InternetInTheLoopRule.java index ff3b66e2c..831871abb 100644 --- a/src/android-plugin/src/main/java/io/ecocode/java/checks/bottleneck/InternetInTheLoopRule.java +++ b/src/android-plugin/src/main/java/io/ecocode/java/checks/bottleneck/InternetInTheLoopRule.java @@ -67,4 +67,4 @@ private void reportIssueIfInLoop(Tree treeToCheck, Tree issueTree) { reportIssueIfInLoop(treeToCheck.parent(), issueTree); } } -} \ No newline at end of file +} diff --git a/src/android-plugin/src/main/java/io/ecocode/java/checks/bottleneck/UncachedDataReceptionRule.java b/src/android-plugin/src/main/java/io/ecocode/java/checks/bottleneck/UncachedDataReceptionRule.java new file mode 100644 index 000000000..2e543b5f3 --- /dev/null +++ b/src/android-plugin/src/main/java/io/ecocode/java/checks/bottleneck/UncachedDataReceptionRule.java @@ -0,0 +1,43 @@ +/* + * ecoCode SonarQube Plugin + * Copyright (C) 2020-2021 Snapp' - Université de Pau et des Pays de l'Adour + * mailto: contact@ecocode.io + * + * 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 io.ecocode.java.checks.bottleneck; + +import io.ecocode.java.checks.helpers.SpecificMethodCheck; +import org.sonar.check.Rule; + +/** + * Check that `install` method of android.net.http.HttpResponseCache is called + */ +@Rule(key = "EBOT004", name = "UncachedDataReception") +public class UncachedDataReceptionRule extends SpecificMethodCheck { + + private static final String ERROR_MESSAGE = "Catching all of the application's HTTP responses to the filesystem."; + private static final String METHOD_NAME = "install"; + private static final String METHOD_OWNER_TYPE = "android.net.http.HttpResponseCache"; + + public UncachedDataReceptionRule() { + super(METHOD_OWNER_TYPE, METHOD_NAME); + } + + @Override + public String getMessage() { + return ERROR_MESSAGE; + } +} diff --git a/src/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/EBOT004_java.html b/src/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/EBOT004_java.html new file mode 100644 index 000000000..6e4c97072 --- /dev/null +++ b/src/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/EBOT004_java.html @@ -0,0 +1,14 @@ + +

Caching all of the application's HTTP responses to the filesystem (application-specific cache directory) so they may + be reused, allow to save energy. To that purpose the class HttpResponseCachesupports HttpURLConnection + and HttpsURLConnection; there is no platform-provided cache for further clients. Installing the cache + at application startup is done with the static method HttpResponseCache.install(File directory, long + maxSize). +

+

Noncompliant Code Example

+
+    
+        HttpResponseCache.install(file,1L);
+    
+
+ diff --git a/src/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/EBOT004_java.json b/src/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/EBOT004_java.json new file mode 100644 index 000000000..63756fe56 --- /dev/null +++ b/src/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/EBOT004_java.json @@ -0,0 +1,15 @@ +{ + "title": "Bottleneck: Uncached Data Reception", + "type": "CODE_SMELL", + "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "30min" + }, + "tags": [ + "bottleneck", + "environment", + "ecocode" + ], + "defaultSeverity": "Minor" +} diff --git a/src/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ecocode_java_profile.json b/src/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ecocode_java_profile.json index 9a58e794d..5c37fa803 100644 --- a/src/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ecocode_java_profile.json +++ b/src/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ecocode_java_profile.json @@ -30,6 +30,7 @@ "ESOB008", "ESOB010", "ESOB011", - "ESOB012" + "ESOB012", + "EBOT004" ] -} \ No newline at end of file +} diff --git a/src/android-plugin/src/test/files/bottleneck/UncachedDataReceptionCheck.java b/src/android-plugin/src/test/files/bottleneck/UncachedDataReceptionCheck.java new file mode 100644 index 000000000..84edf1f1f --- /dev/null +++ b/src/android-plugin/src/test/files/bottleneck/UncachedDataReceptionCheck.java @@ -0,0 +1,13 @@ +package android.net.http; + +public final class HttpResponseCache { + + public void test() { + File file = new File(""); + HttpResponseCache.install(file, 1L);// Noncompliant {{Catching all of the application's HTTP responses to the filesystem.}} + } + + public static synchronized HttpResponseCache install(File directory, long maxSize) throws IOException { + throw new RuntimeException("Stub!"); + } +} diff --git a/src/android-plugin/src/test/java/io/ecocode/java/JavaRulesDefinitionTest.java b/src/android-plugin/src/test/java/io/ecocode/java/JavaRulesDefinitionTest.java index 06e5c2e5a..24ad1602e 100644 --- a/src/android-plugin/src/test/java/io/ecocode/java/JavaRulesDefinitionTest.java +++ b/src/android-plugin/src/test/java/io/ecocode/java/JavaRulesDefinitionTest.java @@ -227,6 +227,12 @@ private void assertRuleProperties(Repository repository) { assertThat(thriftyNotification.name()).isEqualTo("Sobriety: Thrifty Notification"); assertThat(thriftyNotification.debtRemediationFunction().type()).isEqualTo(Type.CONSTANT_ISSUE); assertThat(thriftyNotification.type()).isEqualTo(RuleType.CODE_SMELL); + + Rule uncachedDataReception = repository.rule("EBOT004"); + assertThat(uncachedDataReception).isNotNull(); + assertThat(uncachedDataReception.name()).isEqualTo("Bottleneck: Uncached Data Reception"); + assertThat(uncachedDataReception.debtRemediationFunction().type()).isEqualTo(Type.CONSTANT_ISSUE); + assertThat(uncachedDataReception.type()).isEqualTo(RuleType.CODE_SMELL); } private void assertAllRuleParametersHaveDescription(Repository repository) { diff --git a/src/android-plugin/src/test/java/io/ecocode/java/checks/bottleneck/UncachedDataReceptionRuleTest.java b/src/android-plugin/src/test/java/io/ecocode/java/checks/bottleneck/UncachedDataReceptionRuleTest.java new file mode 100644 index 000000000..cb4ce3ab5 --- /dev/null +++ b/src/android-plugin/src/test/java/io/ecocode/java/checks/bottleneck/UncachedDataReceptionRuleTest.java @@ -0,0 +1,14 @@ +package io.ecocode.java.checks.bottleneck; + +import org.junit.Test; +import org.sonar.java.checks.verifier.JavaCheckVerifier; + +public class UncachedDataReceptionRuleTest { + + @Test + public void verifyUncachedDataReception() { + JavaCheckVerifier.newVerifier().onFile("src/test/files/bottleneck/UncachedDataReceptionCheck.java") + .withCheck(new UncachedDataReceptionRule()) + .verifyIssues(); + } +} diff --git a/src/codenarc-converter/CodeNarc/gradlew b/src/codenarc-converter/CodeNarc/gradlew old mode 100644 new mode 100755 From 2fe674aa085633513d4b9f39272eac7f459bbd53 Mon Sep 17 00:00:00 2001 From: Lyes ABROUS <77389193+Lsdla@users.noreply.github.com> Date: Thu, 2 Jun 2022 19:18:43 +0200 Subject: [PATCH 018/119] Revert "Features/bottleneck ebot004 " --- .idea/.gitignore | 8 -- .idea/compiler.xml | 17 --- .idea/ecoCode.iml | 9 -- .idea/encodings.xml | 14 -- .idea/gradle.xml | 18 --- .idea/jarRepositories.xml | 35 ----- .idea/misc.xml | 16 --- .idea/modules.xml | 8 -- .idea/runConfigurations.xml | 10 -- .idea/uiDesigner.xml | 124 ------------------ .idea/vcs.xml | 6 - .../java/io/ecocode/java/JavaCheckList.java | 4 +- .../bottleneck/InternetInTheLoopRule.java | 2 +- .../bottleneck/UncachedDataReceptionRule.java | 43 ------ .../l10n/java/rules/squid/EBOT004_java.html | 14 -- .../l10n/java/rules/squid/EBOT004_java.json | 15 --- .../rules/squid/ecocode_java_profile.json | 5 +- .../UncachedDataReceptionCheck.java | 13 -- .../ecocode/java/JavaRulesDefinitionTest.java | 6 - .../UncachedDataReceptionRuleTest.java | 14 -- src/codenarc-converter/CodeNarc/gradlew | 0 src/docker-compose.yml | 6 +- src/pom.xml | 2 +- 23 files changed, 8 insertions(+), 381 deletions(-) delete mode 100644 .idea/.gitignore delete mode 100644 .idea/compiler.xml delete mode 100644 .idea/ecoCode.iml delete mode 100644 .idea/encodings.xml delete mode 100644 .idea/gradle.xml delete mode 100644 .idea/jarRepositories.xml delete mode 100644 .idea/misc.xml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/runConfigurations.xml delete mode 100644 .idea/uiDesigner.xml delete mode 100644 .idea/vcs.xml delete mode 100644 src/android-plugin/src/main/java/io/ecocode/java/checks/bottleneck/UncachedDataReceptionRule.java delete mode 100644 src/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/EBOT004_java.html delete mode 100644 src/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/EBOT004_java.json delete mode 100644 src/android-plugin/src/test/files/bottleneck/UncachedDataReceptionCheck.java delete mode 100644 src/android-plugin/src/test/java/io/ecocode/java/checks/bottleneck/UncachedDataReceptionRuleTest.java mode change 100755 => 100644 src/codenarc-converter/CodeNarc/gradlew diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 73f69e095..000000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Datasource local storage ignored files -/dataSources/ -/dataSources.local.xml -# Editor-based HTTP Client requests -/httpRequests/ diff --git a/.idea/compiler.xml b/.idea/compiler.xml deleted file mode 100644 index 3e0369ed6..000000000 --- a/.idea/compiler.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/ecoCode.iml b/.idea/ecoCode.iml deleted file mode 100644 index d6ebd4805..000000000 --- a/.idea/ecoCode.iml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml deleted file mode 100644 index 3485ac0f0..000000000 --- a/.idea/encodings.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml deleted file mode 100644 index f0822bd42..000000000 --- a/.idea/gradle.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml deleted file mode 100644 index 995f69966..000000000 --- a/.idea/jarRepositories.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index ccc59f084..000000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 648097b9c..000000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml deleted file mode 100644 index 797acea53..000000000 --- a/.idea/runConfigurations.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml deleted file mode 100644 index e96534fb2..000000000 --- a/.idea/uiDesigner.xml +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 35eb1ddfb..000000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/src/android-plugin/src/main/java/io/ecocode/java/JavaCheckList.java b/src/android-plugin/src/main/java/io/ecocode/java/JavaCheckList.java index 9eaeacabc..d1e2ff247 100644 --- a/src/android-plugin/src/main/java/io/ecocode/java/JavaCheckList.java +++ b/src/android-plugin/src/main/java/io/ecocode/java/JavaCheckList.java @@ -22,7 +22,6 @@ import io.ecocode.java.checks.batch.JobCoalesceRule; import io.ecocode.java.checks.batch.SensorCoalesceRule; import io.ecocode.java.checks.bottleneck.InternetInTheLoopRule; -import io.ecocode.java.checks.bottleneck.UncachedDataReceptionRule; import io.ecocode.java.checks.bottleneck.UncompressedDataTransmissionRule; import io.ecocode.java.checks.bottleneck.WifiMulticastLockRule; import io.ecocode.java.checks.idleness.*; @@ -82,8 +81,7 @@ public static List> getJavaChecks() { SensorCoalesceRule.class, JobCoalesceRule.class, SaveModeAwarenessRule.class, - ThriftyGeolocationCriteriaRule.class, - UncachedDataReceptionRule.class + ThriftyGeolocationCriteriaRule.class )); } diff --git a/src/android-plugin/src/main/java/io/ecocode/java/checks/bottleneck/InternetInTheLoopRule.java b/src/android-plugin/src/main/java/io/ecocode/java/checks/bottleneck/InternetInTheLoopRule.java index 831871abb..ff3b66e2c 100644 --- a/src/android-plugin/src/main/java/io/ecocode/java/checks/bottleneck/InternetInTheLoopRule.java +++ b/src/android-plugin/src/main/java/io/ecocode/java/checks/bottleneck/InternetInTheLoopRule.java @@ -67,4 +67,4 @@ private void reportIssueIfInLoop(Tree treeToCheck, Tree issueTree) { reportIssueIfInLoop(treeToCheck.parent(), issueTree); } } -} +} \ No newline at end of file diff --git a/src/android-plugin/src/main/java/io/ecocode/java/checks/bottleneck/UncachedDataReceptionRule.java b/src/android-plugin/src/main/java/io/ecocode/java/checks/bottleneck/UncachedDataReceptionRule.java deleted file mode 100644 index 2e543b5f3..000000000 --- a/src/android-plugin/src/main/java/io/ecocode/java/checks/bottleneck/UncachedDataReceptionRule.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * ecoCode SonarQube Plugin - * Copyright (C) 2020-2021 Snapp' - Université de Pau et des Pays de l'Adour - * mailto: contact@ecocode.io - * - * 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 io.ecocode.java.checks.bottleneck; - -import io.ecocode.java.checks.helpers.SpecificMethodCheck; -import org.sonar.check.Rule; - -/** - * Check that `install` method of android.net.http.HttpResponseCache is called - */ -@Rule(key = "EBOT004", name = "UncachedDataReception") -public class UncachedDataReceptionRule extends SpecificMethodCheck { - - private static final String ERROR_MESSAGE = "Catching all of the application's HTTP responses to the filesystem."; - private static final String METHOD_NAME = "install"; - private static final String METHOD_OWNER_TYPE = "android.net.http.HttpResponseCache"; - - public UncachedDataReceptionRule() { - super(METHOD_OWNER_TYPE, METHOD_NAME); - } - - @Override - public String getMessage() { - return ERROR_MESSAGE; - } -} diff --git a/src/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/EBOT004_java.html b/src/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/EBOT004_java.html deleted file mode 100644 index 6e4c97072..000000000 --- a/src/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/EBOT004_java.html +++ /dev/null @@ -1,14 +0,0 @@ - -

Caching all of the application's HTTP responses to the filesystem (application-specific cache directory) so they may - be reused, allow to save energy. To that purpose the class HttpResponseCachesupports HttpURLConnection - and HttpsURLConnection; there is no platform-provided cache for further clients. Installing the cache - at application startup is done with the static method HttpResponseCache.install(File directory, long - maxSize). -

-

Noncompliant Code Example

-
-    
-        HttpResponseCache.install(file,1L);
-    
-
- diff --git a/src/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/EBOT004_java.json b/src/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/EBOT004_java.json deleted file mode 100644 index 63756fe56..000000000 --- a/src/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/EBOT004_java.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "title": "Bottleneck: Uncached Data Reception", - "type": "CODE_SMELL", - "status": "ready", - "remediation": { - "func": "Constant\/Issue", - "constantCost": "30min" - }, - "tags": [ - "bottleneck", - "environment", - "ecocode" - ], - "defaultSeverity": "Minor" -} diff --git a/src/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ecocode_java_profile.json b/src/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ecocode_java_profile.json index 5c37fa803..9a58e794d 100644 --- a/src/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ecocode_java_profile.json +++ b/src/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ecocode_java_profile.json @@ -30,7 +30,6 @@ "ESOB008", "ESOB010", "ESOB011", - "ESOB012", - "EBOT004" + "ESOB012" ] -} +} \ No newline at end of file diff --git a/src/android-plugin/src/test/files/bottleneck/UncachedDataReceptionCheck.java b/src/android-plugin/src/test/files/bottleneck/UncachedDataReceptionCheck.java deleted file mode 100644 index 84edf1f1f..000000000 --- a/src/android-plugin/src/test/files/bottleneck/UncachedDataReceptionCheck.java +++ /dev/null @@ -1,13 +0,0 @@ -package android.net.http; - -public final class HttpResponseCache { - - public void test() { - File file = new File(""); - HttpResponseCache.install(file, 1L);// Noncompliant {{Catching all of the application's HTTP responses to the filesystem.}} - } - - public static synchronized HttpResponseCache install(File directory, long maxSize) throws IOException { - throw new RuntimeException("Stub!"); - } -} diff --git a/src/android-plugin/src/test/java/io/ecocode/java/JavaRulesDefinitionTest.java b/src/android-plugin/src/test/java/io/ecocode/java/JavaRulesDefinitionTest.java index 24ad1602e..06e5c2e5a 100644 --- a/src/android-plugin/src/test/java/io/ecocode/java/JavaRulesDefinitionTest.java +++ b/src/android-plugin/src/test/java/io/ecocode/java/JavaRulesDefinitionTest.java @@ -227,12 +227,6 @@ private void assertRuleProperties(Repository repository) { assertThat(thriftyNotification.name()).isEqualTo("Sobriety: Thrifty Notification"); assertThat(thriftyNotification.debtRemediationFunction().type()).isEqualTo(Type.CONSTANT_ISSUE); assertThat(thriftyNotification.type()).isEqualTo(RuleType.CODE_SMELL); - - Rule uncachedDataReception = repository.rule("EBOT004"); - assertThat(uncachedDataReception).isNotNull(); - assertThat(uncachedDataReception.name()).isEqualTo("Bottleneck: Uncached Data Reception"); - assertThat(uncachedDataReception.debtRemediationFunction().type()).isEqualTo(Type.CONSTANT_ISSUE); - assertThat(uncachedDataReception.type()).isEqualTo(RuleType.CODE_SMELL); } private void assertAllRuleParametersHaveDescription(Repository repository) { diff --git a/src/android-plugin/src/test/java/io/ecocode/java/checks/bottleneck/UncachedDataReceptionRuleTest.java b/src/android-plugin/src/test/java/io/ecocode/java/checks/bottleneck/UncachedDataReceptionRuleTest.java deleted file mode 100644 index cb4ce3ab5..000000000 --- a/src/android-plugin/src/test/java/io/ecocode/java/checks/bottleneck/UncachedDataReceptionRuleTest.java +++ /dev/null @@ -1,14 +0,0 @@ -package io.ecocode.java.checks.bottleneck; - -import org.junit.Test; -import org.sonar.java.checks.verifier.JavaCheckVerifier; - -public class UncachedDataReceptionRuleTest { - - @Test - public void verifyUncachedDataReception() { - JavaCheckVerifier.newVerifier().onFile("src/test/files/bottleneck/UncachedDataReceptionCheck.java") - .withCheck(new UncachedDataReceptionRule()) - .verifyIssues(); - } -} diff --git a/src/codenarc-converter/CodeNarc/gradlew b/src/codenarc-converter/CodeNarc/gradlew old mode 100755 new mode 100644 diff --git a/src/docker-compose.yml b/src/docker-compose.yml index 5bfe2b9fb..541ba112d 100644 --- a/src/docker-compose.yml +++ b/src/docker-compose.yml @@ -17,9 +17,9 @@ services: - type: bind source: ./java-plugin/target/ecocode-java-plugin-1.0.0-SNAPSHOT.jar target: /opt/sonarqube/extensions/plugins/ecocode-java-plugin-1.0.0-SNAPSHOT.jar - #- type: bind - # source: ./php-plugin/target/ecocode-php-plugin-1.0.0-SNAPSHOT.jar - # target: /opt/sonarqube/extensions/plugins/ecocode-php-plugin-1.0.0-SNAPSHOT.jar + - type: bind + source: ./php-plugin/target/ecocode-php-plugin-1.0.0-SNAPSHOT.jar + target: /opt/sonarqube/extensions/plugins/ecocode-php-plugin-1.0.0-SNAPSHOT.jar - type: bind source: ./python-plugin/target/ecocode-python-plugin-1.0.0-SNAPSHOT.jar target: /opt/sonarqube/extensions/plugins/ecocode-python-plugin-1.0.0-SNAPSHOT.jar diff --git a/src/pom.xml b/src/pom.xml index 394266c18..112dff9f4 100644 --- a/src/pom.xml +++ b/src/pom.xml @@ -28,7 +28,7 @@ java-plugin - + php-plugin python-plugin codenarc-converter android-plugin From 2ecec786b959f25fdef74c5e4a30484d9b3d65cd Mon Sep 17 00:00:00 2001 From: Julien Bureau Date: Fri, 3 Jun 2022 01:39:30 +0200 Subject: [PATCH 019/119] Utiliser System.arraycopy pour copier des arrays --- .../fr/cnumr/java/checks/ArrayCopyCheck.java | 180 +++++++++++ .../cnumr/l10n/java/rules/java/GRPS0027.html | 24 ++ .../cnumr/l10n/java/rules/java/GRPS0027.json | 13 + .../src/test/files/ArrayCopyCheck.java | 293 ++++++++++++++++++ .../cnumr/java/checks/ArrayCopyCheckTest.java | 19 ++ 5 files changed, 529 insertions(+) create mode 100644 src/java-plugin/src/main/java/fr/cnumr/java/checks/ArrayCopyCheck.java create mode 100644 src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRPS0027.html create mode 100644 src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRPS0027.json create mode 100644 src/java-plugin/src/test/files/ArrayCopyCheck.java create mode 100644 src/java-plugin/src/test/java/fr/cnumr/java/checks/ArrayCopyCheckTest.java diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/checks/ArrayCopyCheck.java b/src/java-plugin/src/main/java/fr/cnumr/java/checks/ArrayCopyCheck.java new file mode 100644 index 000000000..e6ab8a34c --- /dev/null +++ b/src/java-plugin/src/main/java/fr/cnumr/java/checks/ArrayCopyCheck.java @@ -0,0 +1,180 @@ +package fr.cnumr.java.checks; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import org.sonar.check.Priority; +import org.sonar.check.Rule; +import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; +import org.sonar.plugins.java.api.tree.ArrayAccessExpressionTree; +import org.sonar.plugins.java.api.tree.AssignmentExpressionTree; +import org.sonar.plugins.java.api.tree.BlockTree; +import org.sonar.plugins.java.api.tree.CatchTree; +import org.sonar.plugins.java.api.tree.DoWhileStatementTree; +import org.sonar.plugins.java.api.tree.ExpressionStatementTree; +import org.sonar.plugins.java.api.tree.ExpressionTree; +import org.sonar.plugins.java.api.tree.ForStatementTree; +import org.sonar.plugins.java.api.tree.IdentifierTree; +import org.sonar.plugins.java.api.tree.IfStatementTree; +import org.sonar.plugins.java.api.tree.StatementTree; +import org.sonar.plugins.java.api.tree.Tree; +import org.sonar.plugins.java.api.tree.Tree.Kind; +import org.sonar.plugins.java.api.tree.TryStatementTree; +import org.sonar.plugins.java.api.tree.WhileStatementTree; + +@Rule(key = "GRPS0027", name = "Developpement", description = ArrayCopyCheck.MESSAGERULE, priority = Priority.MINOR, tags = { + "CODE_SMELL" }) +public class ArrayCopyCheck extends IssuableSubscriptionVisitor { + + protected static final String MESSAGERULE = "Utiliser System.arraycopy pour copier des arrays"; + + @Override + public List nodesToVisit() { + return Arrays.asList(Kind.FOR_STATEMENT, Kind.WHILE_STATEMENT, Kind.DO_STATEMENT); + } + + /** + * Check a node. Report issue when found. + */ + @Override + public void visitNode(final Tree tree) { + final List assignments = extractAssignments(tree); + for (final AssignmentExpressionTree assignment : assignments) { + final ExpressionTree destVariable = assignment.variable(); + final ExpressionTree srcEspression = assignment.expression(); + if (isArray(destVariable) && isArray(srcEspression)) { + final String destArray = getArrayIdentifier(destVariable); + final String srcArray = getArrayIdentifier(srcEspression); + if (!destArray.equals(srcArray)) { + reportIssue(tree, MESSAGERULE); + } + } + } + } + + /** + * Extract variable's name of array + * + * @param expression of Array + * @return Array's name + */ + private String getArrayIdentifier(final ExpressionTree expression) { + if (expression instanceof ArrayAccessExpressionTree) { + final ExpressionTree identifier = ((ArrayAccessExpressionTree) expression).expression(); + if (identifier instanceof IdentifierTree) { + return ((IdentifierTree) identifier).identifierToken().text(); + } + } + return null; + } + + /** + * Verify if expression is an Array + * + * @param expression + * @return true if instance of ArrayAccessExpressionTree, false else + */ + private boolean isArray(final ExpressionTree expression) { + return expression instanceof ArrayAccessExpressionTree; + } + + /** + * Extract all assignments + * + * @param tree + * @return + */ + private List extractAssignments(final Tree tree) { + + // Determine blocks to be analyzed + final List blocks = getBlocksOfCode(tree); + + // Analyze blocks + final List result = new ArrayList<>(); + for (final BlockTree block : blocks) { + result.addAll(extractAssignments(block)); + } + return result; + } + + /** + * Extract nested blocks of code + * + * @param tree + * @return + */ + private List getBlocksOfCode(final Tree tree) { + final List blocks = new ArrayList<>(); + if (tree instanceof ForStatementTree) { + addBlock(blocks, ((ForStatementTree) tree).statement()); + } else if (tree instanceof WhileStatementTree) { + addBlock(blocks, ((WhileStatementTree) tree).statement()); + } else if (tree instanceof DoWhileStatementTree) { + addBlock(blocks, ((DoWhileStatementTree) tree).statement()); + } else if (tree instanceof IfStatementTree) { + addBlock(blocks, ((IfStatementTree) tree).thenStatement()); + addBlock(blocks, ((IfStatementTree) tree).elseStatement()); + } else if (tree instanceof TryStatementTree) { + final TryStatementTree tryTree = (TryStatementTree) tree; + addBlock(blocks, tryTree.block()); + addBlock(blocks, extractCatchBlocks(tryTree)); + addBlock(blocks, tryTree.finallyBlock()); + } + return blocks; + } + + /** + * Assignments extraction from block of code. + * + * @param block + * @return + */ + private List extractAssignments(final BlockTree block) { + // Prepare useful predicates + final Predicate blocksPredicate = statement -> statement.is(Kind.IF_STATEMENT) + || statement.is(Kind.TRY_STATEMENT); + final Predicate assignmentPredicate = statement -> statement.is(Kind.EXPRESSION_STATEMENT) + && ((ExpressionStatementTree) statement).expression().is(Kind.ASSIGNMENT); + + // Filter expressions to find assignments + final List result = block.body().stream().filter(assignmentPredicate) + .map(assign -> (AssignmentExpressionTree) ((ExpressionStatementTree) assign).expression()) + .collect(Collectors.toList()); + + // Recursive loop for nested blocks, add nested assignments to results + final List ifStatements = block.body().stream().filter(blocksPredicate) + .collect(Collectors.toList()); + for (final StatementTree ifstatement : ifStatements) { + result.addAll(extractAssignments(ifstatement)); + } + return result; + } + + /** + * Extract all blocks of code from try/catch statement + * + * @param tryTree + * @return Array of StatementTree + */ + private BlockTree[] extractCatchBlocks(final TryStatementTree tryTree) { + final List catches = tryTree.catches(); + return catches.stream().map(CatchTree::block).collect(Collectors.toList()).toArray(new BlockTree[0]); + } + + /** + * Add a BlockTree in list after type checking + * + * @param blocks + * @param statements + */ + private void addBlock(final List blocks, final StatementTree... statements) { + for (final StatementTree statement : statements) { + if (statement instanceof BlockTree) { + blocks.add((BlockTree) statement); + } + } + } +} diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRPS0027.html b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRPS0027.html new file mode 100644 index 000000000..77d802ada --- /dev/null +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRPS0027.html @@ -0,0 +1,24 @@ +

Utiliser System.arraycopy pour copier des arrays

+

+Les programmes passent la plupart du temps dans des boucles. Celles-ci peuvent �tre consommatrices en ressource, plus particuli�rement quand elles int�grent des traitements lourds (acc�s IO�). De plus, la taille des donn�es et des traitements � l�int�rieur des boucles ne va pas permettre d�utiliser pleinement les m�canismes mat�riels tels le cache ou les m�canismes d�optimisation des compilateurs.
+La copie d�array est par exemple potentiellement une source de non-performance si elle est mal con�ue. En effet, l�utilisation d�une simple boucle de recopie peut �tre deux fois plus consommatrice que des m�thodes d�di�es.
+Les boucles doivent �tre optimis�es pour diminuer le temps de traitement et utiliser pleinement les m�canismes et optimisations mat�riels et processeurs.
+Dans le cas de la recopie de tableau (array), on utilisera la m�thode native System.arraycopy.
+On pourra aussi utiliser copyOf ou clone qui sont l�g�rement moins performantes.
+On proscrira la m�thode de recopie par boucle. +

+

M�thode � proscrire :

+
+	int len = array.length;
+	boolean[] copy = new boolean[array.length];
+	for (int i = 0; i < len; i++) {
+  		copy[i] = array[i];
+	}
+	return copy;
+
+

M�thode � privil�gier :

+
+	int[] copy = new int[array.length];
+	System.arraycopy(array, 0, copy, 0, array.length);
+	return copy;
+
diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRPS0027.json b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRPS0027.json new file mode 100644 index 000000000..c396965be --- /dev/null +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRPS0027.json @@ -0,0 +1,13 @@ +{ + "title": "Utiliser System.arraycopy pour copier des arrays", + "type": "CODE_SMELL", + "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "20min" + }, + "tags": [ + "eco-conception" + ], + "defaultSeverity": "Minor" +} \ No newline at end of file diff --git a/src/java-plugin/src/test/files/ArrayCopyCheck.java b/src/java-plugin/src/test/files/ArrayCopyCheck.java new file mode 100644 index 000000000..743639274 --- /dev/null +++ b/src/java-plugin/src/test/files/ArrayCopyCheck.java @@ -0,0 +1,293 @@ +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; + +class TestClass { + + public void copyArrayOK() { + final int len = 5; + final boolean[] src = new boolean[len]; + boolean[] dest = new boolean[len]; + + // Copy with clone + dest = src.clone(); + + // Copy with System.arraycopy() + System.arraycopy(src, 0, dest, 0, src.length); + + // Copy with Arrays.copyOf() + dest = Arrays.copyOf(src, src.length); + } + + public void nonRegression() { + final int len = 5; + final boolean[] src = new boolean[len]; + boolean[] dest = new boolean[len]; + + // Simple assignation + for (int i = 0; i < len; i++) { + dest[i] = true; + } + + // Objects assignations + String a = null; + String b = "Sample Value"; + for (int i = 0; i < len; i++) { + a = b; + } + } + + public void copyWithForLoop() { + final int len = 5; + final boolean[] src = new boolean[len]; + boolean[] dest = new boolean[len]; + + // Simple copy + for (int i = 0; i < len; i++) { // Noncompliant + dest[i] = src[i]; + } + + // Copy with nested conditions + for (int i = 0; i < len; i++) { // Noncompliant + if(i + 2 < len) { + dest[i] = src[i + 2]; + } + } + + // Copy with nested ELSE conditions + for (int i = 0; i < len; i++) { // Noncompliant + if(i + 2 >= len) { + i++; + } else { + dest[i] = src[i + 2]; + } + } + + // Copy with more nested conditions + for (int i = 0; i < len; i++) { // Noncompliant + if(i + 2 < len) { + if(dest != null) { + if(src != null) { + if(i > 1 && i + 2 < src.length) { + dest[i] = src[i + 2]; + } + } + } + } + } + + // Copy nested by try/catch + for (int i = 0; i < len; i++) { // Noncompliant + try { + dest[i] = src[i]; + } catch (RuntimeException e) { + e.printStackTrace(); + } + } + + // Copy nested by try/catch and if + for (int i = 0; i < len; i++) { // Noncompliant + try { + if(dest != null) { + dest[i] = src[i]; + } + } catch (RuntimeException e) { + e.printStackTrace(); + } + } + + // Copy nested by try/catch in catch + for (int i = 0; i < len; i++) { // Noncompliant + try { + dest.toString(); + } catch (RuntimeException e) { + if(dest != null) { + dest[i] = src[i]; + } + } + } + + // Copy nested by try/catch in finally + for (int i = 0; i < len; i++) { // Noncompliant + try { + dest.toString(); + } catch (RuntimeException e) { + e.printStackTrace(); + } finally { + dest[i] = src[i]; + } + } + + // Array transformation + for (int i = 0; i < len; i++) { + dest[i] = transform(src[i]); + } + } + + public void copyWithWhileLoop() { + final int len = 5; + final boolean[] src = new boolean[len]; + boolean[] dest = new boolean[len]; + + // Simple copy + int i = 0; + while (i < len) { // Noncompliant + dest[i] = src[i]; + i++; + } + + // Copy with nested conditions + i = 0; + while (i < len) { // Noncompliant + if(i + 2 < len) { + dest[i] = src[i + 2]; + } + i++; + } + + // Copy with nested ELSE conditions + i = 0; + while (i < len) { // Noncompliant + if(i + 2 >= len) { + i++; + } else { + dest[i] = src[i + 2]; + } + i++; + } + + // Copy with more nested conditions + i = 0; + while (i < len) { // Noncompliant + if(i + 2 < len) { + if(dest != null) { + if(src != null) { + if(i > 1 && i + 2 < src.length) { + dest[i] = src[i + 2]; + } + } + } + } + i++; + } + + // Copy nested by try/catch and if + i = 0; + while (i < len) { // Noncompliant + try { + if(dest != null) { + dest[i] = src[i]; + } + } catch (RuntimeException e) { + e.printStackTrace(); + } + i++; + } + + // Copy nested by try/catch in catch + i = 0; + while (i < len) { // Noncompliant + try { + dest.toString(); + } catch (RuntimeException e) { + if(dest != null) { + dest[i] = src[i]; + } + } + i++; + } + + // Array transformation + i = 0; + while (i < len) { + dest[i] = transform(src[i]); + i++; + } + } + + public void copyWithDoWhileLoop() { + final int len = 5; + final boolean[] src = new boolean[len]; + boolean[] dest = new boolean[len]; + + // Simple copy + int i = 0; + do { // Noncompliant + dest[i] = src[i]; + i++; + } while (i < len); + + // Copy with nested conditions + i = 0; + do { // Noncompliant + if(i + 2 < len) { + dest[i] = src[i + 2]; + } + i++; + } while (i < len); + + // Copy with nested ELSE conditions + i = 0; + do { // Noncompliant + if(i + 2 >= len) { + i++; + } else { + dest[i] = src[i + 2]; + } + i++; + } while (i < len); + + // Copy with more nested conditions + i = 0; + do { // Noncompliant + if(i + 2 < len) { + if(dest != null) { + if(src != null) { + if(i > 1 && i + 2 < src.length) { + dest[i] = src[i + 2]; + } + } + } + } + i++; + } while (i < len); + + // Copy nested by try/catch and if + i = 0; + do { // Noncompliant + try { + if(dest != null) { + dest[i] = src[i]; + } + } catch (RuntimeException e) { + e.printStackTrace(); + } + i++; + } while (i < len); + + // Copy nested by try/catch in catch + i = 0; + do { // Noncompliant + try { + dest.toString(); + } catch (RuntimeException e) { + if(dest != null) { + dest[i] = src[i]; + } + } + i++; + } while (i < len); + + // Array transformation + i = 0; + do { + dest[i] = transform(src[i]); + i++; + } while (i < len); + } + + private boolean transform(boolean a) { + return !a; + } + +} \ No newline at end of file diff --git a/src/java-plugin/src/test/java/fr/cnumr/java/checks/ArrayCopyCheckTest.java b/src/java-plugin/src/test/java/fr/cnumr/java/checks/ArrayCopyCheckTest.java new file mode 100644 index 000000000..9d2577ef2 --- /dev/null +++ b/src/java-plugin/src/test/java/fr/cnumr/java/checks/ArrayCopyCheckTest.java @@ -0,0 +1,19 @@ +package fr.cnumr.java.checks; + +import org.junit.jupiter.api.Test; +import org.sonar.java.checks.verifier.CheckVerifier; + +class ArrayCopyCheckTest { + + /** + * @formatter:off + */ + @Test + void test() { + CheckVerifier.newVerifier() + .onFile("src/test/files/ArrayCopyCheck.java") + .withCheck(new ArrayCopyCheck()) + .verifyIssues(); + } + +} \ No newline at end of file From c1a7ce5a3d60c08809b5d5644c257ec3fe33081e Mon Sep 17 00:00:00 2001 From: Julien Bureau Date: Fri, 3 Jun 2022 08:43:37 +0200 Subject: [PATCH 020/119] Add rule declaration --- src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java b/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java index 7bcd53578..41458a238 100644 --- a/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java +++ b/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java @@ -41,6 +41,7 @@ public static List> getChecks() { public static List> getJavaChecks() { return Collections.unmodifiableList(Arrays.asList( + ArrayCopyCheck.class, IncrementCheck.class, NoFunctionCallWhenDeclaringForLoop.class, AvoidSQLRequestInLoop.class, From 05203eff907c5be3bd8116d48e4c7a00ae8f8153 Mon Sep 17 00:00:00 2001 From: Julien Bureau Date: Fri, 3 Jun 2022 08:44:05 +0200 Subject: [PATCH 021/119] Add anti-reg TU --- src/java-plugin/src/test/files/ArrayCopyCheck.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/java-plugin/src/test/files/ArrayCopyCheck.java b/src/java-plugin/src/test/files/ArrayCopyCheck.java index 743639274..e300fed0d 100644 --- a/src/java-plugin/src/test/files/ArrayCopyCheck.java +++ b/src/java-plugin/src/test/files/ArrayCopyCheck.java @@ -29,6 +29,11 @@ public void nonRegression() { dest[i] = true; } + // Edit same array + for (int i = 0; i < len-1; i++) { + dest[i] = dest[i+1]; + } + // Objects assignations String a = null; String b = "Sample Value"; From decd6eed422670a258923ea4c7f4fc82ae9b336e Mon Sep 17 00:00:00 2001 From: Hertout Julien Date: Fri, 3 Jun 2022 09:45:47 +0200 Subject: [PATCH 022/119] Make CodeNarc gradlew executable on unix system --- src/codenarc-converter/CodeNarc/gradlew | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 src/codenarc-converter/CodeNarc/gradlew diff --git a/src/codenarc-converter/CodeNarc/gradlew b/src/codenarc-converter/CodeNarc/gradlew old mode 100644 new mode 100755 From 1e06f4d49b25915434b2802afb594a7c8217e831 Mon Sep 17 00:00:00 2001 From: Jules Delecour <72793427+jules-delecour-dav@users.noreply.github.com> Date: Fri, 3 Jun 2022 10:38:08 +0200 Subject: [PATCH 023/119] Update build.yml --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ceaaf4d43..977e5dc9f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,7 +2,7 @@ name: Build on: push: branches: - - master + - main pull_request: types: [opened, synchronize, reopened] jobs: From c9e545ba56454803f7294c37f1406c3334ad8919 Mon Sep 17 00:00:00 2001 From: u$f Date: Fri, 3 Jun 2022 12:19:48 +0200 Subject: [PATCH 024/119] java_batch_update --- .../main/java/fr/cnumr/java/RulesList.java | 3 +- .../checks/AvoidSetConstantInBatchUpdate.java | 75 +++++++ .../java/checks/ConstOrLiteralDeclare.java | 198 ++++++++++++++++++ .../fr/cnumr/l10n/java/rules/java/S78.html | 30 +++ .../fr/cnumr/l10n/java/rules/java/S78.json | 13 ++ .../AvoidSetConstantInBatchUpdateCheck.java | 140 +++++++++++++ .../java/MyJavaFileCheckRegistrarTest.java | 2 +- .../AvoidSetConstantInBatchInsertTest.java | 16 ++ 8 files changed, 475 insertions(+), 2 deletions(-) create mode 100644 src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidSetConstantInBatchUpdate.java create mode 100644 src/java-plugin/src/main/java/fr/cnumr/java/checks/ConstOrLiteralDeclare.java create mode 100644 src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S78.html create mode 100644 src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S78.json create mode 100644 src/java-plugin/src/test/files/AvoidSetConstantInBatchUpdateCheck.java create mode 100644 src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidSetConstantInBatchInsertTest.java diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java b/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java index 7bcd53578..02bcb6d94 100644 --- a/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java +++ b/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java @@ -46,7 +46,8 @@ public static List> getJavaChecks() { AvoidSQLRequestInLoop.class, AvoidFullSQLRequest.class, UseCorrectForLoop.class, - UnnecessarilyAssignValuesToVariables.class + UnnecessarilyAssignValuesToVariables.class, + AvoidSetConstantInBatchUpdate.class )); } diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidSetConstantInBatchUpdate.java b/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidSetConstantInBatchUpdate.java new file mode 100644 index 000000000..e2a90f258 --- /dev/null +++ b/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidSetConstantInBatchUpdate.java @@ -0,0 +1,75 @@ +package fr.cnumr.java.checks; + +import static fr.cnumr.java.checks.ConstOrLiteralDeclare.isLiteral; +import static java.util.Arrays.asList; +import static org.sonar.plugins.java.api.semantic.Type.Primitives.INT; +import static org.sonar.plugins.java.api.tree.Tree.Kind.MEMBER_SELECT; +import static org.sonar.plugins.java.api.tree.Tree.Kind.METHOD_INVOCATION; + +import java.sql.PreparedStatement; +import java.util.List; +import java.util.stream.Stream; + +import org.sonar.check.Priority; +import org.sonar.check.Rule; +import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; +import org.sonar.plugins.java.api.semantic.MethodMatchers; +import org.sonar.plugins.java.api.tree.BaseTreeVisitor; +import org.sonar.plugins.java.api.tree.MemberSelectExpressionTree; +import org.sonar.plugins.java.api.tree.MethodInvocationTree; +import org.sonar.plugins.java.api.tree.Tree; +import org.sonar.plugins.java.api.tree.Tree.Kind; + +@Rule(key = "S78", name = "Developpement", + description = AvoidSetConstantInBatchUpdate.MESSAGERULE, + priority = Priority.MINOR, + tags = { "bug" }) + +public class AvoidSetConstantInBatchUpdate extends IssuableSubscriptionVisitor { + + protected static final String MESSAGERULE = "Avoid setting constants in batch insert"; + private final AvoidSetConstantInBatchUpdateVisitor visitorInFile = new AvoidSetConstantInBatchUpdateVisitor(); + + @Override + public List nodesToVisit() { + return asList( + Tree.Kind.FOR_EACH_STATEMENT, + Tree.Kind.FOR_STATEMENT, + Tree.Kind.WHILE_STATEMENT, + Tree.Kind.DO_STATEMENT); + } + + @Override + public void visitNode(Tree tree) { + tree.accept(visitorInFile); + } + + private class AvoidSetConstantInBatchUpdateVisitor extends BaseTreeVisitor { + + private final MethodMatchers setters = MethodMatchers.create().ofSubTypes(PreparedStatement.class.getName()) + .names("setBoolean", "setByte", "setShort", "setInt", "setLong", "setFloat", "setDouble", + "setBigDecimal", "setString") + .addParametersMatcher(args-> args.size() == 2 && args.get(0).isPrimitive(INT)).build(); + + @Override + public void visitMethodInvocation(MethodInvocationTree tree) { + if (setters.matches(tree) && isConstant(tree.arguments().get(1))) { + reportIssue(tree, MESSAGERULE); + } else { + super.visitMethodInvocation(tree); + } + } + } + + private static final boolean isConstant(Tree arg) { + + if (arg.is(METHOD_INVOCATION)) { + MethodInvocationTree m = (MethodInvocationTree) arg; + return Stream.of(ConstOrLiteralDeclare.values()).anyMatch(o-> o.isLiteralDeclare(m)); + } else if (arg.is(MEMBER_SELECT)) { + MemberSelectExpressionTree m = (MemberSelectExpressionTree) arg; + return Stream.of(ConstOrLiteralDeclare.values()).anyMatch(o-> o.isPublicMember(m)); + } + return isLiteral(arg); + } +} \ No newline at end of file diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/checks/ConstOrLiteralDeclare.java b/src/java-plugin/src/main/java/fr/cnumr/java/checks/ConstOrLiteralDeclare.java new file mode 100644 index 000000000..f3bc1f5df --- /dev/null +++ b/src/java-plugin/src/main/java/fr/cnumr/java/checks/ConstOrLiteralDeclare.java @@ -0,0 +1,198 @@ +package fr.cnumr.java.checks; + +import static org.sonar.plugins.java.api.semantic.MethodMatchers.create; +import static org.sonar.plugins.java.api.tree.Tree.Kind.BOOLEAN_LITERAL; +import static org.sonar.plugins.java.api.tree.Tree.Kind.CHAR_LITERAL; +import static org.sonar.plugins.java.api.tree.Tree.Kind.DOUBLE_LITERAL; +import static org.sonar.plugins.java.api.tree.Tree.Kind.FLOAT_LITERAL; +import static org.sonar.plugins.java.api.tree.Tree.Kind.INT_LITERAL; +import static org.sonar.plugins.java.api.tree.Tree.Kind.LONG_LITERAL; +import static org.sonar.plugins.java.api.tree.Tree.Kind.STRING_LITERAL; +import static org.sonar.plugins.java.api.tree.Tree.Kind.TYPE_CAST; + +import java.math.BigDecimal; +import java.util.Set; + +import org.sonar.plugins.java.api.semantic.MethodMatchers; +import org.sonar.plugins.java.api.tree.MemberSelectExpressionTree; +import org.sonar.plugins.java.api.tree.MethodInvocationTree; +import org.sonar.plugins.java.api.tree.Tree; +import org.sonar.plugins.java.api.tree.TypeCastTree; + +enum ConstOrLiteralDeclare { + + BOOLEAN { + @Override + String className() { + return Boolean.class.getName(); + } + @Override + Set publicMembers() { + return Set.of("TRUE", "FALSE"); + } + @Override + MethodMatchers methodMatchers() { + return DEFAULT_METHOD_MATCHERS; + } + }, + + BYTE { + @Override + String className() { + return Byte.class.getName(); + } + @Override + Set publicMembers() { + return NUMBER_DEFAULT_MEMBERS; + } + @Override + MethodMatchers methodMatchers() { + return DEFAULT_METHOD_MATCHERS; + } + }, + + SHORT { + @Override + String className() { + return Short.class.getName(); + } + @Override + Set publicMembers() { + return NUMBER_DEFAULT_MEMBERS; + } + @Override + MethodMatchers methodMatchers() { + return DEFAULT_METHOD_MATCHERS; + } + }, + + INTEGER { + @Override + String className() { + return Integer.class.getName(); + } + + @Override + Set publicMembers() { + return NUMBER_DEFAULT_MEMBERS; + } + @Override + MethodMatchers methodMatchers() { + return DEFAULT_METHOD_MATCHERS; + } + }, + + LONG { + @Override + String className() { + return Long.class.getName(); + } + @Override + Set publicMembers() { + return NUMBER_DEFAULT_MEMBERS; + } + @Override + MethodMatchers methodMatchers() { + return DEFAULT_METHOD_MATCHERS; + } + }, + + FLOAT { + @Override + String className() { + return Float.class.getName(); + } + @Override + Set publicMembers() { + return NUMBER_DEFAULT_MEMBERS; + } + @Override + MethodMatchers methodMatchers() { + return DEFAULT_METHOD_MATCHERS; + } + }, + + DOUBLE { + @Override + String className() { + return Double.class.getName(); + } + @Override + Set publicMembers() { + return NUMBER_DEFAULT_MEMBERS; + } + @Override + MethodMatchers methodMatchers() { + return DEFAULT_METHOD_MATCHERS; + } + }, + + CHARACTER { + @Override + String className() { + return Character.class.getName(); + } + @Override + Set publicMembers() { + return NUMBER_DEFAULT_MEMBERS; + } + @Override + MethodMatchers methodMatchers() { + return DEFAULT_METHOD_MATCHERS; + } + }, + + BIGDECIMAL { + + @Override + String className() { + return BigDecimal.class.getName(); + } + + @Override + Set publicMembers() { + return Set.of("ZERO", "ONE", "TEN"); + } + @Override + MethodMatchers methodMatchers() { + return DEFAULT_METHOD_MATCHERS; + } + }; + + public boolean isPublicMember(MemberSelectExpressionTree tree) { + + return className().equals(tree.expression().symbolType().fullyQualifiedName()) //strong check + && publicMembers().contains(tree.identifier().toString()); + } + + public boolean isLiteralDeclare(MethodInvocationTree tree) { + + return methodMatchers().matches(tree) + && tree.arguments().stream().allMatch(ConstOrLiteralDeclare::isLiteral); + } + + abstract String className(); + + abstract Set publicMembers(); + + abstract MethodMatchers methodMatchers(); + + private static final Set NUMBER_DEFAULT_MEMBERS = Set.of("MIN_VALUE", "MAX_VALUE"); + + private static final MethodMatchers DEFAULT_METHOD_MATCHERS = create() + .ofSubTypes(Number.class.getName(), Boolean.class.getName(), Character.class.getName()).names("valueOf") + .addParametersMatcher(args-> !args.isEmpty()).build(); + + public static final boolean isLiteral(Tree arg) { + if (arg.is(TYPE_CAST)) { + arg = ((TypeCastTree) arg).expression(); + } + return arg.is(BOOLEAN_LITERAL) || + arg.is(INT_LITERAL) || + arg.is(LONG_LITERAL) || + arg.is(FLOAT_LITERAL) || + arg.is(DOUBLE_LITERAL) || + arg.is(STRING_LITERAL) || + arg.is(CHAR_LITERAL); + } +} \ No newline at end of file diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S78.html b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S78.html new file mode 100644 index 000000000..f28ae5d91 --- /dev/null +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S78.html @@ -0,0 +1,30 @@ +

Don't set const parameter in batch update => Put its in query

+

Noncompliant Code Example

+
+    public void foo() {
+    	...
+    	String query = "insert into mytable values(?,?,?)";
+        ...
+        for(DummyClass o : list) {
+			stmt.setInt(1, 123);
+			stmt.setString(2, o.getName());
+			stmt.setDouble(3, o.getPrice());
+			stmt.addBatch();
+		}
+        ...
+    }
+
+

Compliant Solution

+
+    public void foo() {
+    	...
+    	String query = "insert into mytable values(123,?,?)";
+        ...
+        for(DummyClass o : list) {
+			stmt.setString(1, o.getName());
+			stmt.setDouble(2, o.getPrice());
+			stmt.addBatch();
+		}
+        ...
+    }
+
diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S78.json b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S78.json new file mode 100644 index 000000000..5317370df --- /dev/null +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S78.json @@ -0,0 +1,13 @@ +{ + "title": "Don't set const parameter in batch update => Put its in query", + "type": "CODE_SMELL", + "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "15min" + }, + "tags": [ + "eco-conception", "eco-sql" + ], + "defaultSeverity": "Minor" +} \ No newline at end of file diff --git a/src/java-plugin/src/test/files/AvoidSetConstantInBatchUpdateCheck.java b/src/java-plugin/src/test/files/AvoidSetConstantInBatchUpdateCheck.java new file mode 100644 index 000000000..31992cb36 --- /dev/null +++ b/src/java-plugin/src/test/files/AvoidSetConstantInBatchUpdateCheck.java @@ -0,0 +1,140 @@ +package fr.cnumr.java.checks; + +import java.math.BigDecimal; +import java.sql.PreparedStatement; +import java.util.regex.Pattern; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +class AvoidSetConstantInBatchUpdateCheck { + + void literalSQLrequest() { //dirty call + + int x = 0; + Connection con=DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe","system","oracle"); + PreparedStatement stmt=con.prepareStatement("insert into Emp values(?,?,?,?)"); + stmt.setInt(1,101); + stmt.setString(2,"Ratan"); + stmt.setBigDecimal(3, Bigdecimal.ONE); + stmt.setBigDecimal(4, BigDecimal.valueOf(x)); + stmt.setBoolean(5, Boolean.valueOf("true")); + int i=stmt.executeUpdate(); + System.out.println(i+" records inserted"); + con.close(); + } + + void batchInsertInForLoop(int[] data) { + + Connection con=DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe","system","oracle"); + PreparedStatement stmt=con.prepareStatement("insert into Emp values(?,?,?,?,?,?,?,?,?,?,?)"); + for(int i=0; i Date: Fri, 3 Jun 2022 12:24:27 +0200 Subject: [PATCH 025/119] edit --- .../fr/cnumr/java/checks/AvoidSetConstantInBatchUpdate.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidSetConstantInBatchUpdate.java b/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidSetConstantInBatchUpdate.java index e2a90f258..b9691e7a2 100644 --- a/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidSetConstantInBatchUpdate.java +++ b/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidSetConstantInBatchUpdate.java @@ -27,7 +27,7 @@ public class AvoidSetConstantInBatchUpdate extends IssuableSubscriptionVisitor { - protected static final String MESSAGERULE = "Avoid setting constants in batch insert"; + protected static final String MESSAGERULE = "Avoid setting constants in batch update"; private final AvoidSetConstantInBatchUpdateVisitor visitorInFile = new AvoidSetConstantInBatchUpdateVisitor(); @Override From dad69045fbb50073b567c129035f0d63da6c6525 Mon Sep 17 00:00:00 2001 From: Cyrille Chopelet Date: Fri, 3 Jun 2022 12:58:10 +0200 Subject: [PATCH 026/119] [CodeNarc] Create a script for CodeNarc preparation --- .github/workflows/build.yml | 12 +++------- src/INSTALL.md | 2 +- src/codenarc-converter/pom.xml | 40 ---------------------------------- src/prepare-codenarc | 12 ++++++++++ src/prepare-codenarc.bat | 8 +++++++ 5 files changed, 24 insertions(+), 50 deletions(-) create mode 100755 src/prepare-codenarc create mode 100644 src/prepare-codenarc.bat diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 977e5dc9f..87b5fd7e7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -31,16 +31,10 @@ jobs: restore-keys: ${{ runner.os }}-m2 - name: Setup Gradle uses: gradle/gradle-build-action@v2 - - name: Execute Gradle build CodeNarc - working-directory: ./src/codenarc-converter/CodeNarc - run: | - chmod +x gradlew - ./gradlew build -x test - - name: Execute Maven build CodeNarc - working-directory: ./src/codenarc-converter + - name: Prepare CodeNarc dependency + working-directory: ./src run: | - mvn initialize - mvn clean package + ./prepare-codenarc - name: Build and analyze working-directory: ./src env: diff --git a/src/INSTALL.md b/src/INSTALL.md index b86dbf64c..db4a3ae13 100644 --- a/src/INSTALL.md +++ b/src/INSTALL.md @@ -42,7 +42,7 @@ CodeNarc must be built separately. Please see the following steps: Build CodeNarc (Gradle 6.9.2, Java 11), then add this custom-built CodeNarc to Maven dependencies: ```sh -mvn initialize +./prepare-codenarc ``` diff --git a/src/codenarc-converter/pom.xml b/src/codenarc-converter/pom.xml index c6497d448..8952c6c76 100644 --- a/src/codenarc-converter/pom.xml +++ b/src/codenarc-converter/pom.xml @@ -125,24 +125,6 @@ exec-maven-plugin 3.0.0 - - - generate-codenarc - initialize - - exec - - - CodeNarc/gradlew - - -p - CodeNarc - build - -x - test - - - run-codenarc-converter generate-test-sources @@ -158,28 +140,6 @@ - - - org.apache.maven.plugins - maven-install-plugin - 2.5.2 - - - deploy-codenarc-to-local-repo - initialize - - install-file - - - ${project.basedir}/CodeNarc/build/libs/CodeNarc-${codenarc.version}.jar - org.codenarc - CodeNarc - ${codenarc.version} - jar - - - - diff --git a/src/prepare-codenarc b/src/prepare-codenarc new file mode 100755 index 000000000..73d237e12 --- /dev/null +++ b/src/prepare-codenarc @@ -0,0 +1,12 @@ +#!/usr/bin/env sh + +# Define CodeNarc version +codenarcVersion="2.2.2" + +# Build CodeNarc +cd codenarc-converter/CodeNarc +./gradlew + +# Deploy to local repository +mvn install:install-file -Dfile=build/libs/CodeNarc-${codenarcVersion}.jar -DgroupId=org.codenarc -DartifactId=CodeNarc -Dversion=${codenarcVersion} -Dpackaging=jar + diff --git a/src/prepare-codenarc.bat b/src/prepare-codenarc.bat new file mode 100644 index 000000000..e660b55bb --- /dev/null +++ b/src/prepare-codenarc.bat @@ -0,0 +1,8 @@ +REM == Define CodeNarc version +set codenarc_version=2.2.2 + +REM == Build CodeNarc +cd codenarc-converter/CodeNarc + +REM == Deploy to local repository +mvn install:install-file -Dfile=build/libs/CodeNarc-%codenarc_version%.jar -DgroupId=org.codenarc -DartifactId=CodeNarc -Dversion=%codenarc_version% -Dpackaging=jar From aed7d6c4c3675a01f56c77e373c638770918a35a Mon Sep 17 00:00:00 2001 From: Cyrille Chopelet Date: Fri, 3 Jun 2022 13:16:02 +0200 Subject: [PATCH 027/119] [CodeNarc] Fix preparation script typos --- src/prepare-codenarc | 4 ++-- src/prepare-codenarc.bat | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/prepare-codenarc b/src/prepare-codenarc index 73d237e12..bd1257ff8 100755 --- a/src/prepare-codenarc +++ b/src/prepare-codenarc @@ -5,8 +5,8 @@ codenarcVersion="2.2.2" # Build CodeNarc cd codenarc-converter/CodeNarc -./gradlew +./gradlew build -x test # Deploy to local repository -mvn install:install-file -Dfile=build/libs/CodeNarc-${codenarcVersion}.jar -DgroupId=org.codenarc -DartifactId=CodeNarc -Dversion=${codenarcVersion} -Dpackaging=jar +mvn -B install:install-file -Dfile=build/libs/CodeNarc-${codenarcVersion}.jar -DgroupId=org.codenarc -DartifactId=CodeNarc -Dversion=${codenarcVersion} -Dpackaging=jar diff --git a/src/prepare-codenarc.bat b/src/prepare-codenarc.bat index e660b55bb..f552a6f87 100644 --- a/src/prepare-codenarc.bat +++ b/src/prepare-codenarc.bat @@ -3,6 +3,7 @@ set codenarc_version=2.2.2 REM == Build CodeNarc cd codenarc-converter/CodeNarc +./gradlew build -x test REM == Deploy to local repository -mvn install:install-file -Dfile=build/libs/CodeNarc-%codenarc_version%.jar -DgroupId=org.codenarc -DartifactId=CodeNarc -Dversion=%codenarc_version% -Dpackaging=jar +mvn -B install:install-file -Dfile=build/libs/CodeNarc-%codenarc_version%.jar -DgroupId=org.codenarc -DartifactId=CodeNarc -Dversion=%codenarc_version% -Dpackaging=jar From fe27871d0da23a5e9e813d15c80f17e15b785650 Mon Sep 17 00:00:00 2001 From: Mourad MAMASSI Date: Fri, 3 Jun 2022 13:17:54 +0200 Subject: [PATCH 028/119] :zap: creating GRSP0028 --- .../main/java/fr/cnumr/java/RulesList.java | 3 +- .../checks/OptimizeReadFileException.java | 48 +++++++++++++++++++ .../cnumr/l10n/java/rules/java/GRSP0028.html | 29 +++++++++++ .../cnumr/l10n/java/rules/java/GRSP0028.json | 13 +++++ .../files/OptimizeReadFileExceptionCheck.java | 19 ++++++++ .../java/MyJavaFileCheckRegistrarTest.java | 2 +- .../OptimizeReadFileExceptionCheckTest.java | 16 +++++++ 7 files changed, 128 insertions(+), 2 deletions(-) create mode 100644 src/java-plugin/src/main/java/fr/cnumr/java/checks/OptimizeReadFileException.java create mode 100644 src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRSP0028.html create mode 100644 src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRSP0028.json create mode 100644 src/java-plugin/src/test/files/OptimizeReadFileExceptionCheck.java create mode 100644 src/java-plugin/src/test/java/fr/cnumr/java/checks/OptimizeReadFileExceptionCheckTest.java diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java b/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java index 7bcd53578..eec47b9fb 100644 --- a/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java +++ b/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java @@ -46,7 +46,8 @@ public static List> getJavaChecks() { AvoidSQLRequestInLoop.class, AvoidFullSQLRequest.class, UseCorrectForLoop.class, - UnnecessarilyAssignValuesToVariables.class + UnnecessarilyAssignValuesToVariables.class, + OptimizeReadFileException.class )); } diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/checks/OptimizeReadFileException.java b/src/java-plugin/src/main/java/fr/cnumr/java/checks/OptimizeReadFileException.java new file mode 100644 index 000000000..3e0f6fb08 --- /dev/null +++ b/src/java-plugin/src/main/java/fr/cnumr/java/checks/OptimizeReadFileException.java @@ -0,0 +1,48 @@ +package fr.cnumr.java.checks; + + +import org.sonar.check.Priority; +import org.sonar.check.Rule; +import org.sonar.java.model.statement.CatchTreeImpl; +import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; +import org.sonar.plugins.java.api.tree.CatchTree; +import org.sonar.plugins.java.api.tree.NewClassTree; +import org.sonar.plugins.java.api.tree.Tree; +import org.sonar.plugins.java.api.tree.Tree.Kind; +import org.sonar.plugins.java.api.tree.TryStatementTree; + +import java.util.Arrays; +import java.util.List; + +@Rule( + key = "GRSP0028", + name = "Developpement", + description = OptimizeReadFileException.MESSAGERULE, + priority = Priority.MINOR, + tags = {"bug"}) +public class OptimizeReadFileException extends IssuableSubscriptionVisitor { + + protected static final String MESSAGERULE = "Optimize Read File Exception"; + private boolean isFileNotFoundException = false; + + @Override + public List nodesToVisit() { + return Arrays.asList(Kind.TRY_STATEMENT, Kind.NEW_CLASS); + } + + @Override + public void visitNode(Tree tree) { + + if(tree.kind().getAssociatedInterface().equals(NewClassTree.class) && this.isFileNotFoundException){ + NewClassTree newClassTree = (NewClassTree) tree; + if(newClassTree.identifier().symbolType().toString().equals("FileInputStream")){ + reportIssue(tree, MESSAGERULE); + } + }else{ + TryStatementTree tryStatementTree = (TryStatementTree) tree; + List catchTreeList = tryStatementTree.catches(); + this.isFileNotFoundException = catchTreeList.stream().anyMatch(catchTree -> catchTree.parameter().type().symbolType().toString().equals("FileNotFoundException")); + } + return; + } +} \ No newline at end of file diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRSP0028.html b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRSP0028.html new file mode 100644 index 000000000..d37bcef22 --- /dev/null +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRSP0028.html @@ -0,0 +1,29 @@ +

Optimize read file exception

+

Noncompliant Code Example

+
+		public void readPreferences(String filename) {
+		  //...
+		  InputStream in = null;
+		  try {
+			in = new FileInputStream(filename);
+		  } catch (FileNotFoundException e) {
+			logger.log(e);
+		  }
+		  in.read(...);
+		  //...
+		}
+
+
+

Compliant Solution

+
+		public void readPreferences(String filename)
+			throws IllegalArgumentException,
+				   FileNotFoundException, IOException {
+		  if (filename == null) {
+			throw new IllegalArgumentException ("filename is null");
+		  }  //if
+		  //...
+		  InputStream in = new FileInputStream(filename);
+		  //...
+		}
+
diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRSP0028.json b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRSP0028.json new file mode 100644 index 000000000..f22f6b6c2 --- /dev/null +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRSP0028.json @@ -0,0 +1,13 @@ +{ + "title": "Optimize read file exception", + "type": "CODE_SMELL", + "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "5min" + }, + "tags": [ + "eco-conception" + ], + "defaultSeverity": "Minor" +} \ No newline at end of file diff --git a/src/java-plugin/src/test/files/OptimizeReadFileExceptionCheck.java b/src/java-plugin/src/test/files/OptimizeReadFileExceptionCheck.java new file mode 100644 index 000000000..4aeccf549 --- /dev/null +++ b/src/java-plugin/src/test/files/OptimizeReadFileExceptionCheck.java @@ -0,0 +1,19 @@ +package fr.cnumr.java.checks; + +import java.util.Arrays; +import java.util.List; + +class ReadFile { + ReadFile(ReadFile readFile) { + } + public void readPreferences(String filename) { + //... + InputStream in = null; + try { + in = new FileInputStream(filename); // Noncompliant + } catch (FileNotFoundException e) { + logger.log(e); + } + //... + } +} \ No newline at end of file diff --git a/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java b/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java index bbc12316c..81ad838e2 100644 --- a/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java +++ b/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java @@ -32,7 +32,7 @@ void checkNumberRules() { MyJavaFileCheckRegistrar registrar = new MyJavaFileCheckRegistrar(); registrar.register(context); - assertThat(context.checkClasses()).hasSize(6); + assertThat(context.checkClasses()).hasSize(7); assertThat(context.testCheckClasses()).isEmpty(); } diff --git a/src/java-plugin/src/test/java/fr/cnumr/java/checks/OptimizeReadFileExceptionCheckTest.java b/src/java-plugin/src/test/java/fr/cnumr/java/checks/OptimizeReadFileExceptionCheckTest.java new file mode 100644 index 000000000..008e58b23 --- /dev/null +++ b/src/java-plugin/src/test/java/fr/cnumr/java/checks/OptimizeReadFileExceptionCheckTest.java @@ -0,0 +1,16 @@ +package fr.cnumr.java.checks; + +import org.junit.jupiter.api.Test; +import org.sonar.java.checks.verifier.JavaCheckVerifier; + +class OptimizeReadFileExceptionCheckTest { + + @Test + void test() { + JavaCheckVerifier.newVerifier() + .onFile("src/test/files/OptimizeReadFileExceptionCheck.java") + .withCheck(new OptimizeReadFileException()) + .verifyIssues(); + } + +} \ No newline at end of file From ad01564272bc93162abb91e97dd1c24222907026 Mon Sep 17 00:00:00 2001 From: Julien Bureau Date: Fri, 3 Jun 2022 13:12:49 +0200 Subject: [PATCH 029/119] Gestion des foreachs --- .../fr/cnumr/java/checks/ArrayCopyCheck.java | 171 +++++++++++---- .../src/test/files/ArrayCopyCheck.java | 195 ++++++++++++++++++ .../java/MyJavaFileCheckRegistrarTest.java | 19 +- 3 files changed, 340 insertions(+), 45 deletions(-) diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/checks/ArrayCopyCheck.java b/src/java-plugin/src/main/java/fr/cnumr/java/checks/ArrayCopyCheck.java index e6ab8a34c..9150318e8 100644 --- a/src/java-plugin/src/main/java/fr/cnumr/java/checks/ArrayCopyCheck.java +++ b/src/java-plugin/src/main/java/fr/cnumr/java/checks/ArrayCopyCheck.java @@ -16,6 +16,7 @@ import org.sonar.plugins.java.api.tree.DoWhileStatementTree; import org.sonar.plugins.java.api.tree.ExpressionStatementTree; import org.sonar.plugins.java.api.tree.ExpressionTree; +import org.sonar.plugins.java.api.tree.ForEachStatement; import org.sonar.plugins.java.api.tree.ForStatementTree; import org.sonar.plugins.java.api.tree.IdentifierTree; import org.sonar.plugins.java.api.tree.IfStatementTree; @@ -23,17 +24,27 @@ import org.sonar.plugins.java.api.tree.Tree; import org.sonar.plugins.java.api.tree.Tree.Kind; import org.sonar.plugins.java.api.tree.TryStatementTree; +import org.sonar.plugins.java.api.tree.VariableTree; import org.sonar.plugins.java.api.tree.WhileStatementTree; -@Rule(key = "GRPS0027", name = "Developpement", description = ArrayCopyCheck.MESSAGERULE, priority = Priority.MINOR, tags = { - "CODE_SMELL" }) +/** + * Array Copy Check + * @formatter:off + * @author Aubay + */ +@Rule(key = "GRPS0027", + name = "Developpement", + description = ArrayCopyCheck.MESSAGERULE, + priority = Priority.MINOR, + tags = { "bug" }) public class ArrayCopyCheck extends IssuableSubscriptionVisitor { + //@formatter:on protected static final String MESSAGERULE = "Utiliser System.arraycopy pour copier des arrays"; @Override public List nodesToVisit() { - return Arrays.asList(Kind.FOR_STATEMENT, Kind.WHILE_STATEMENT, Kind.DO_STATEMENT); + return Arrays.asList(Kind.FOR_STATEMENT, Kind.WHILE_STATEMENT, Kind.DO_STATEMENT, Kind.FOR_EACH_STATEMENT); } /** @@ -41,14 +52,52 @@ public List nodesToVisit() { */ @Override public void visitNode(final Tree tree) { - final List assignments = extractAssignments(tree); - for (final AssignmentExpressionTree assignment : assignments) { + // Determine blocks to be analyzed + final List blocs = getBlocsOfCode(tree); + + // Analyze blocks + for (final Bloc bloc : blocs) { + if (bloc.isForeach()) { + handleForEachAssignments(tree, bloc); + } + handleAssignments(tree, bloc); + } + } + + /** + * Handle for-each assignments controls. + * + * @param tree + * @param bloc + */ + private void handleForEachAssignments(final Tree tree, final Bloc bloc) { + for (final AssignmentExpressionTree assignment : extractAssignments(tree, bloc)) { + final ExpressionTree destination = assignment.variable(); + final ExpressionTree source = assignment.expression(); + if (isArray(destination) && isVariable(source)) { + final String destinationIdentifier = getArrayIdentifier(destination); + final String sourceIdentifier = ((IdentifierTree) source).name(); + if (bloc.getValue().equals(sourceIdentifier) && !bloc.getIterable().equals(destinationIdentifier)) { + reportIssue(tree, MESSAGERULE); + } + } + } + } + + /** + * Handle assignments controls. + * + * @param tree + * @param bloc + */ + private void handleAssignments(final Tree tree, final Bloc bloc) { + for (final AssignmentExpressionTree assignment : extractAssignments(tree, bloc)) { final ExpressionTree destVariable = assignment.variable(); final ExpressionTree srcEspression = assignment.expression(); if (isArray(destVariable) && isArray(srcEspression)) { final String destArray = getArrayIdentifier(destVariable); final String srcArray = getArrayIdentifier(srcEspression); - if (!destArray.equals(srcArray)) { + if (destArray != null && !destArray.equals(srcArray)) { reportIssue(tree, MESSAGERULE); } } @@ -82,22 +131,13 @@ private boolean isArray(final ExpressionTree expression) { } /** - * Extract all assignments + * Verify if expression is an variable * - * @param tree + * @param source * @return */ - private List extractAssignments(final Tree tree) { - - // Determine blocks to be analyzed - final List blocks = getBlocksOfCode(tree); - - // Analyze blocks - final List result = new ArrayList<>(); - for (final BlockTree block : blocks) { - result.addAll(extractAssignments(block)); - } - return result; + private boolean isVariable(final ExpressionTree source) { + return source instanceof IdentifierTree; } /** @@ -106,33 +146,40 @@ private List extractAssignments(final Tree tree) { * @param tree * @return */ - private List getBlocksOfCode(final Tree tree) { - final List blocks = new ArrayList<>(); + private List getBlocsOfCode(final Tree tree) { + final List blocs = new ArrayList<>(); if (tree instanceof ForStatementTree) { - addBlock(blocks, ((ForStatementTree) tree).statement()); + addBloc(blocs, ((ForStatementTree) tree).statement()); + } else if (tree instanceof ForEachStatement) { + addForEachBloc(blocs, ((ForEachStatement) tree).statement(), ((ForEachStatement) tree).variable(), + ((ForEachStatement) tree).expression()); } else if (tree instanceof WhileStatementTree) { - addBlock(blocks, ((WhileStatementTree) tree).statement()); + addBloc(blocs, ((WhileStatementTree) tree).statement()); } else if (tree instanceof DoWhileStatementTree) { - addBlock(blocks, ((DoWhileStatementTree) tree).statement()); + addBloc(blocs, ((DoWhileStatementTree) tree).statement()); } else if (tree instanceof IfStatementTree) { - addBlock(blocks, ((IfStatementTree) tree).thenStatement()); - addBlock(blocks, ((IfStatementTree) tree).elseStatement()); + addBloc(blocs, ((IfStatementTree) tree).thenStatement()); + addBloc(blocs, ((IfStatementTree) tree).elseStatement()); } else if (tree instanceof TryStatementTree) { final TryStatementTree tryTree = (TryStatementTree) tree; - addBlock(blocks, tryTree.block()); - addBlock(blocks, extractCatchBlocks(tryTree)); - addBlock(blocks, tryTree.finallyBlock()); + addBloc(blocs, tryTree.block()); + addBloc(blocs, extractCatchBlocks(tryTree)); + addBloc(blocs, tryTree.finallyBlock()); } - return blocks; + return blocs; } /** * Assignments extraction from block of code. * + * @param tree + * * @param block * @return */ - private List extractAssignments(final BlockTree block) { + private List extractAssignments(final Tree tree, final Bloc bloc) { + final BlockTree block = bloc.getBlockTree(); + // Prepare useful predicates final Predicate blocksPredicate = statement -> statement.is(Kind.IF_STATEMENT) || statement.is(Kind.TRY_STATEMENT); @@ -148,7 +195,10 @@ private List extractAssignments(final BlockTree block) final List ifStatements = block.body().stream().filter(blocksPredicate) .collect(Collectors.toList()); for (final StatementTree ifstatement : ifStatements) { - result.addAll(extractAssignments(ifstatement)); + final List blocs = getBlocsOfCode(ifstatement); + for (final Bloc b : blocs) { + result.addAll(extractAssignments(tree, b)); + } } return result; } @@ -165,16 +215,65 @@ private BlockTree[] extractCatchBlocks(final TryStatementTree tryTree) { } /** - * Add a BlockTree in list after type checking + * Add a Bloc in list after type checking * - * @param blocks + * @param blocs * @param statements */ - private void addBlock(final List blocks, final StatementTree... statements) { + private void addBloc(final List blocs, final StatementTree... statements) { for (final StatementTree statement : statements) { if (statement instanceof BlockTree) { - blocks.add((BlockTree) statement); + blocs.add(new Bloc((BlockTree) statement)); } } } + + /** + * Add a Bloc in list after type checking + * + * @param blocs + * @param statement + * @param variable + * @param expression + */ + private void addForEachBloc(final List blocs, final StatementTree statement, final VariableTree variable, + final ExpressionTree expression) { + if (statement instanceof BlockTree && expression instanceof IdentifierTree) { + blocs.add(new Bloc((BlockTree) statement, ((IdentifierTree) expression).identifierToken().text(), + variable.simpleName().identifierToken().text())); + } + } + + private static class Bloc { + private final BlockTree blockTree; + private String iterable; + private String value; + + public Bloc(final BlockTree blockTree, final String iterable, final String value) { + this.blockTree = blockTree; + this.iterable = iterable; + this.value = value; + } + + public boolean isForeach() { + return iterable != null && value != null; + } + + public Bloc(final BlockTree blockTree) { + this.blockTree = blockTree; + } + + public BlockTree getBlockTree() { + return blockTree; + } + + public String getIterable() { + return iterable; + } + + public String getValue() { + return value; + } + + } } diff --git a/src/java-plugin/src/test/files/ArrayCopyCheck.java b/src/java-plugin/src/test/files/ArrayCopyCheck.java index e300fed0d..88129a1ab 100644 --- a/src/java-plugin/src/test/files/ArrayCopyCheck.java +++ b/src/java-plugin/src/test/files/ArrayCopyCheck.java @@ -129,6 +129,201 @@ public void copyWithForLoop() { } } + public void copyWithForEachLoop() { + final int len = 5; + final boolean[] src = new boolean[len]; + boolean[] dest = new boolean[len]; + + // Simple copy by foreach + int i = -1; + for (boolean b : src) { // Noncompliant + dest[++i] = b; + } + + // Copy with nested conditions by foreach + i = -1; + for (boolean b : src) { // Noncompliant + if(b) { + dest[++i] = b; + } + } + + // Copy with nested ELSE conditions by foreach + i = -1; + for (boolean b : src) { // Noncompliant + if(i + 2 >= len) { + i++; + } else { + dest[++i] = b; + } + } + + // Copy with more nested conditions + i = -1; + for (boolean b : src) { // Noncompliant + if(i + 2 < len) { + if(dest != null) { + if(src != null) { + if(i > 1 && i + 2 < src.length) { + dest[++i] = b; + } + } + } + } + } + + // Copy nested by try/catch + i = -1; + for (boolean b : src) { // Noncompliant + try { + dest[++i] = b; + } catch (RuntimeException e) { + e.printStackTrace(); + } + } + + // Copy nested by try/catch and if + i = -1; + for (boolean b : src) { // Noncompliant + try { + if(dest != null) { + dest[++i] = b; + } + } catch (RuntimeException e) { + e.printStackTrace(); + } + } + + // Copy nested by try/catch in catch + i = -1; + for (boolean b : src) { // Noncompliant + try { + dest.toString(); + } catch (RuntimeException e) { + if(dest != null) { + dest[++i] = b; + } + } + } + + // Copy nested by try/catch in finally + i = -1; + for (boolean b : src) { // Noncompliant + try { + dest.toString(); + } catch (RuntimeException e) { + e.printStackTrace(); + } finally { + dest[++i] = b; + } + } + + // Array transformation + i = -1; + for (boolean b : src) { + dest[++i] = transform(b); + } + + // Simple copy + int i = 0; + for (boolean b : src) { // Noncompliant + dest[i] = src[i]; + i++; + } + + // Copy with nested conditions + i = 0; + for (boolean b : src) { // Noncompliant + if(b) { + dest[i] = src[i]; + } + i++; + } + + // Copy with nested ELSE conditions + i = 0; + for (boolean b : src) { // Noncompliant + if(i + 2 >= len) { + i++; + } else { + dest[i] = src[i + 2]; + } + i++; + } + + // Copy with more nested conditions + i = 0; + for (boolean b : src) { // Noncompliant + if(i + 2 < len) { + if(dest != null) { + if(src != null) { + if(i > 1 && i + 2 < src.length) { + dest[i] = src[i + 2]; + } + } + } + } + i++; + } + + // Copy nested by try/catch + i = 0; + for (boolean b : src) { // Noncompliant + try { + dest[i] = src[i]; + } catch (RuntimeException e) { + e.printStackTrace(); + } + i++; + } + + // Copy nested by try/catch and if + i = 0; + for (boolean b : src) { // Noncompliant + try { + if(dest != null) { + dest[i] = src[i]; + } + } catch (RuntimeException e) { + e.printStackTrace(); + } + i++; + } + + // Copy nested by try/catch in catch + i = 0; + for (boolean b : src) { // Noncompliant + try { + dest.toString(); + } catch (RuntimeException e) { + if(dest != null) { + dest[i] = src[i]; + } + } + i++; + } + + // Copy nested by try/catch in finally + i = 0; + for (boolean b : src) { // Noncompliant + try { + dest.toString(); + } catch (RuntimeException e) { + e.printStackTrace(); + } finally { + dest[i] = src[i]; + } + i++; + } + + // Array transformation + i = 0; + for (boolean b : src) { + dest[i] = transform(src[i]); + i++; + } + } + public void copyWithWhileLoop() { final int len = 5; final boolean[] src = new boolean[len]; diff --git a/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java b/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java index bbc12316c..f8e0e0da5 100644 --- a/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java +++ b/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java @@ -19,21 +19,22 @@ */ package fr.cnumr.java; +import static org.assertj.core.api.Assertions.assertThat; + import org.junit.jupiter.api.Test; import org.sonar.plugins.java.api.CheckRegistrar; -import static org.assertj.core.api.Assertions.assertThat; class MyJavaFileCheckRegistrarTest { - @Test - void checkNumberRules() { - CheckRegistrar.RegistrarContext context = new CheckRegistrar.RegistrarContext(); + @Test + void checkNumberRules() { + final CheckRegistrar.RegistrarContext context = new CheckRegistrar.RegistrarContext(); - MyJavaFileCheckRegistrar registrar = new MyJavaFileCheckRegistrar(); - registrar.register(context); + final MyJavaFileCheckRegistrar registrar = new MyJavaFileCheckRegistrar(); + registrar.register(context); - assertThat(context.checkClasses()).hasSize(6); - assertThat(context.testCheckClasses()).isEmpty(); - } + assertThat(context.checkClasses()).hasSize(7); + assertThat(context.testCheckClasses()).isEmpty(); + } } From 695f72df0ec5d81827fbc0853681320b126d6aef Mon Sep 17 00:00:00 2001 From: jberque Date: Fri, 3 Jun 2022 13:29:52 +0200 Subject: [PATCH 030/119] EREL010 _ android-plugin _ DisableObfuscationRule adding rule detecting "minifyEnabled = true" in gradle file --- .../org/sonar/plugins/groovy/cost.csv | 1 + .../sonar/plugins/groovy/profile-default.txt | 3 +- .../org/sonar/plugins/groovy/rules.xml | 38 +++ .../groovy/GroovySonarWayProfileTest.java | 2 +- .../codenarc/CodeNarcRulesDefinitionTest.java | 2 +- .../docs/StarterRuleSet-AllRules.groovy.txt | 3 +- ...arterRuleSet-AllRulesByCategory.groovy.txt | 1 + .../docs/codenarc-rule-index-by-name.md | 1 + .../CodeNarc/docs/codenarc-rule-index.md | 1 + .../CodeNarc/docs/codenarc-rules-ecocode.md | 38 +++ src/codenarc-converter/CodeNarc/gradlew | 0 .../ecocode/DisableObfuscationRule.groovy | 60 +++++ .../codenarc-base-messages.properties | 3 + .../resources/codenarc-base-rules.properties | 1 + .../src/main/resources/rulesets/ecocode.xml | 1 + .../ecocode/DisableObfuscationRuleTest.groovy | 217 ++++++++++++++++++ 16 files changed, 368 insertions(+), 4 deletions(-) mode change 100644 => 100755 src/codenarc-converter/CodeNarc/gradlew create mode 100644 src/codenarc-converter/CodeNarc/src/main/groovy/org/codenarc/rule/ecocode/DisableObfuscationRule.groovy create mode 100644 src/codenarc-converter/CodeNarc/src/test/groovy/org/codenarc/rule/ecocode/DisableObfuscationRuleTest.groovy diff --git a/src/android-plugin/src/main/resources/org/sonar/plugins/groovy/cost.csv b/src/android-plugin/src/main/resources/org/sonar/plugins/groovy/cost.csv index b0416d548..5bbe9134d 100644 --- a/src/android-plugin/src/main/resources/org/sonar/plugins/groovy/cost.csv +++ b/src/android-plugin/src/main/resources/org/sonar/plugins/groovy/cost.csv @@ -1,3 +1,4 @@ ruleKey;remediationFunction;remediationFactor org.codenarc.rule.ecocode.FatAppRule;linear;1h org.codenarc.rule.ecocode.SupportedVersionRangeRule;linear;10min +org.codenarc.rule.ecocode.DisableObfuscationRule;linear;10min diff --git a/src/android-plugin/src/main/resources/org/sonar/plugins/groovy/profile-default.txt b/src/android-plugin/src/main/resources/org/sonar/plugins/groovy/profile-default.txt index 74aa83e73..e454861a5 100644 --- a/src/android-plugin/src/main/resources/org/sonar/plugins/groovy/profile-default.txt +++ b/src/android-plugin/src/main/resources/org/sonar/plugins/groovy/profile-default.txt @@ -1,2 +1,3 @@ org.codenarc.rule.ecocode.FatAppRule -org.codenarc.rule.ecocode.SupportedVersionRangeRule \ No newline at end of file +org.codenarc.rule.ecocode.SupportedVersionRangeRule +org.codenarc.rule.ecocode.DisableObfuscationRule \ No newline at end of file diff --git a/src/android-plugin/src/main/resources/org/sonar/plugins/groovy/rules.xml b/src/android-plugin/src/main/resources/org/sonar/plugins/groovy/rules.xml index 683dfb8a6..02dcaafea 100644 --- a/src/android-plugin/src/main/resources/org/sonar/plugins/groovy/rules.xml +++ b/src/android-plugin/src/main/resources/org/sonar/plugins/groovy/rules.xml @@ -80,6 +80,44 @@ } }
+]]> + code-smell + + + + org.codenarc.rule.ecocode.DisableObfuscationRule + MINOR + + + Using minifyEnabled true will obfuscate code and will have a sligthly negative impact on power consumption at runtime.

+

Example of violations:

+
    android {
+        compileSdk 32
+
+        defaultConfig {
+            applicationId "com.example.sampleForSonar"
+            minSdkVersion 28
+            targetSdkVersion 32
+            versionCode 1
+            versionName "1.0"
+            testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+        }
+
+        buildTypes {
+            release {
+                minifyEnabled true
+                proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+            }
+        }
+        compileOptions {
+            sourceCompatibility JavaVersion.VERSION_1_8
+            targetCompatibility JavaVersion.VERSION_1_8
+        }
+        buildFeatures {
+            viewBinding true
+        }
+    }
+
]]>
code-smell
diff --git a/src/android-plugin/src/test/java/org/sonar/plugins/groovy/GroovySonarWayProfileTest.java b/src/android-plugin/src/test/java/org/sonar/plugins/groovy/GroovySonarWayProfileTest.java index 27a304691..f0e7dd711 100644 --- a/src/android-plugin/src/test/java/org/sonar/plugins/groovy/GroovySonarWayProfileTest.java +++ b/src/android-plugin/src/test/java/org/sonar/plugins/groovy/GroovySonarWayProfileTest.java @@ -45,7 +45,7 @@ public void shouldCreateSonarWayProfile() { profileContext.profile(Groovy.KEY, Groovy.PROFILE_NAME); assertThat(profile.language()).isEqualTo(Groovy.KEY); List activeRules = profile.rules(); - assertThat(activeRules).as("Expected number of rules in profile").hasSize(2); + assertThat(activeRules).as("Expected number of rules in profile").hasSize(3); assertThat(profile.name()).isEqualTo(Groovy.PROFILE_NAME); // Check that we use severity from the read rule and not default one. diff --git a/src/android-plugin/src/test/java/org/sonar/plugins/groovy/codenarc/CodeNarcRulesDefinitionTest.java b/src/android-plugin/src/test/java/org/sonar/plugins/groovy/codenarc/CodeNarcRulesDefinitionTest.java index a636183cc..8a255fab1 100644 --- a/src/android-plugin/src/test/java/org/sonar/plugins/groovy/codenarc/CodeNarcRulesDefinitionTest.java +++ b/src/android-plugin/src/test/java/org/sonar/plugins/groovy/codenarc/CodeNarcRulesDefinitionTest.java @@ -41,6 +41,6 @@ public void test() { assertThat(repository.language()).isEqualTo(Groovy.KEY); List rules = repository.rules(); - assertThat(rules).hasSize(2); + assertThat(rules).hasSize(3); } } diff --git a/src/codenarc-converter/CodeNarc/docs/StarterRuleSet-AllRules.groovy.txt b/src/codenarc-converter/CodeNarc/docs/StarterRuleSet-AllRules.groovy.txt index 990e6a23d..31e595c62 100644 --- a/src/codenarc-converter/CodeNarc/docs/StarterRuleSet-AllRules.groovy.txt +++ b/src/codenarc-converter/CodeNarc/docs/StarterRuleSet-AllRules.groovy.txt @@ -76,7 +76,8 @@ ruleset { CrapMetric // Requires the GMetrics jar and a Cobertura coverage file CyclomaticComplexity // Requires the GMetrics jar DeadCode - DirectConnectionManagement + DirectConnectionManagement + DisableObfuscation DoubleCheckedLocking DoubleNegative DuplicateCaseStatement diff --git a/src/codenarc-converter/CodeNarc/docs/StarterRuleSet-AllRulesByCategory.groovy.txt b/src/codenarc-converter/CodeNarc/docs/StarterRuleSet-AllRulesByCategory.groovy.txt index f2be3ace1..1586a2668 100644 --- a/src/codenarc-converter/CodeNarc/docs/StarterRuleSet-AllRulesByCategory.groovy.txt +++ b/src/codenarc-converter/CodeNarc/docs/StarterRuleSet-AllRulesByCategory.groovy.txt @@ -168,6 +168,7 @@ ruleset { // rulesets/ecocode.xml FatApp SupportedVersionRange + DisableObfuscation // rulesets/enhanced.xml CloneWithoutCloneable diff --git a/src/codenarc-converter/CodeNarc/docs/codenarc-rule-index-by-name.md b/src/codenarc-converter/CodeNarc/docs/codenarc-rule-index-by-name.md index 0afdffe96..e68338d3a 100644 --- a/src/codenarc-converter/CodeNarc/docs/codenarc-rule-index-by-name.md +++ b/src/codenarc-converter/CodeNarc/docs/codenarc-rule-index-by-name.md @@ -79,6 +79,7 @@ title: CodeNarc - Rule Index by Name * [CyclomaticComplexity](./codenarc-rules-size.html#cyclomaticcomplexity-rule) (Requires the GMetrics jar) * [DeadCode](./codenarc-rules-basic.html#deadcode-rule) * [DirectConnectionManagement](./codenarc-rules-jdbc.html#directconnectionmanagement-rule) +* [DisableObfuscation](./codenarc-rules-ecocode.html#disableobfuscation-rule) * [DoubleCheckedLocking](./codenarc-rules-concurrency.html#doublecheckedlocking-rule) * [DoubleNegative](./codenarc-rules-basic.html#doublenegative-rule) * [DuplicateCaseStatement](./codenarc-rules-basic.html#duplicatecasestatement-rule) diff --git a/src/codenarc-converter/CodeNarc/docs/codenarc-rule-index.md b/src/codenarc-converter/CodeNarc/docs/codenarc-rule-index.md index 2221ca5a4..260c3f88c 100644 --- a/src/codenarc-converter/CodeNarc/docs/codenarc-rule-index.md +++ b/src/codenarc-converter/CodeNarc/docs/codenarc-rule-index.md @@ -169,6 +169,7 @@ title: CodeNarc - Rule Index ## [Ecocode](./codenarc-rules-ecocode.html) * [FatApp](./codenarc-rules-ecocode.html#fatapp-rule) * [SupportedVersionRange](./codenarc-rules-ecocode.html#supportedversionrange-rule) +* [DisableObfuscation](./codenarc-rules-ecocode.html#disableobfuscation-rule) ## [Enhanced](./codenarc-rules-enhanced.html) * [CloneWithoutCloneable](./codenarc-rules-enhanced.html#clonewithoutcloneable-rule) diff --git a/src/codenarc-converter/CodeNarc/docs/codenarc-rules-ecocode.md b/src/codenarc-converter/CodeNarc/docs/codenarc-rules-ecocode.md index 67f6cb34c..7bdda726b 100644 --- a/src/codenarc-converter/CodeNarc/docs/codenarc-rules-ecocode.md +++ b/src/codenarc-converter/CodeNarc/docs/codenarc-rules-ecocode.md @@ -82,3 +82,41 @@ android { } } ``` + +## DisableObfuscation Rule + +*Since CodeNarc 2.2.1* + +Using minifyEnabled true will obfuscate code and will have a sligthly negative impact on power consumption at runtime. + +Example of violations: + +``` + android { + compileSdk 32 + + defaultConfig { + applicationId "com.example.sampleForSonar" + minSdkVersion 28 + targetSdkVersion 32 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled true + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + buildFeatures { + viewBinding true + } + } +``` + diff --git a/src/codenarc-converter/CodeNarc/gradlew b/src/codenarc-converter/CodeNarc/gradlew old mode 100644 new mode 100755 diff --git a/src/codenarc-converter/CodeNarc/src/main/groovy/org/codenarc/rule/ecocode/DisableObfuscationRule.groovy b/src/codenarc-converter/CodeNarc/src/main/groovy/org/codenarc/rule/ecocode/DisableObfuscationRule.groovy new file mode 100644 index 000000000..aa2c887eb --- /dev/null +++ b/src/codenarc-converter/CodeNarc/src/main/groovy/org/codenarc/rule/ecocode/DisableObfuscationRule.groovy @@ -0,0 +1,60 @@ +/* + * Copyright 2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.codenarc.rule.ecocode + + +import org.codehaus.groovy.ast.expr.ConstantExpression +import org.codehaus.groovy.ast.expr.MethodCallExpression +import org.codenarc.rule.AbstractAstVisitor +import org.codenarc.rule.AbstractAstVisitorRule +import org.codenarc.util.AstUtil + +/** + * Using minifyEnabled true will obfuscate code and will have a sligthly negative impact on power consumption at runtime. + * + * @author Berque Justin + */ +class DisableObfuscationRule extends AbstractAstVisitorRule { + + String name = 'DisableObfuscation' + int priority = 2 + Class astVisitorClass = DisableObfuscationAstVisitor +} + +class DisableObfuscationAstVisitor extends AbstractAstVisitor { + + @Override + void visitMethodCallExpression(MethodCallExpression methodCallExpression) { + if (((ConstantExpression) methodCallExpression.getMethod()).getValue() == 'minifyEnabled') { + for (Object value : AstUtil.getArgumentsValue(methodCallExpression.getArguments())) { + if (value == true) + addViolation(methodCallExpression, getViolationMessage()) + else { + this.getSourceCode().getLines().each { string -> + if (string.contains(value + ' = true')) { + addViolation(methodCallExpression, getViolationMessage()) + } + } + } + } + } + super.visitMethodCallExpression(methodCallExpression) + } + + private String getViolationMessage() { + return 'Using minifyEnabled true will obfuscate code and will have a sligthly negative impact on power consumption at runtime.' + } +} diff --git a/src/codenarc-converter/CodeNarc/src/main/resources/codenarc-base-messages.properties b/src/codenarc-converter/CodeNarc/src/main/resources/codenarc-base-messages.properties index 5ba5fd43a..fce48fe2f 100644 --- a/src/codenarc-converter/CodeNarc/src/main/resources/codenarc-base-messages.properties +++ b/src/codenarc-converter/CodeNarc/src/main/resources/codenarc-base-messages.properties @@ -1,3 +1,6 @@ +DisableObfuscation.description=Using minifyEnabled true will obfuscate code and will have a sligthly negative impact on power consumption at runtime. +DisableObfuscation.description.html=Using minifyEnabled true will obfuscate code and will have a sligthly negative impact on power consumption at runtime. + SupportedVersionRange.description=The amplitude of supported platform versions should not be too wide, at the risk of making the app too heavy to handle all cases. SupportedVersionRange.description.html=The amplitude of supported platform versions should not be too wide, at the risk of making the app too heavy to handle all cases. diff --git a/src/codenarc-converter/CodeNarc/src/main/resources/codenarc-base-rules.properties b/src/codenarc-converter/CodeNarc/src/main/resources/codenarc-base-rules.properties index 0d9ec5a8c..6df09e8fb 100644 --- a/src/codenarc-converter/CodeNarc/src/main/resources/codenarc-base-rules.properties +++ b/src/codenarc-converter/CodeNarc/src/main/resources/codenarc-base-rules.properties @@ -69,6 +69,7 @@ CoupledTestCase = org.codenarc.rule.junit.CoupledTestCaseRule CrapMetric = org.codenarc.rule.size.CrapMetricRule CyclomaticComplexity = org.codenarc.rule.size.CyclomaticComplexityRule DeadCode = org.codenarc.rule.basic.DeadCodeRule +DisableObfuscation = org.codenarc.rule.ecocode.DisableObfuscationRule DirectConnectionManagement = org.codenarc.rule.jdbc.DirectConnectionManagementRule DoubleCheckedLocking = org.codenarc.rule.concurrency.DoubleCheckedLockingRule DoubleNegative = org.codenarc.rule.basic.DoubleNegativeRule diff --git a/src/codenarc-converter/CodeNarc/src/main/resources/rulesets/ecocode.xml b/src/codenarc-converter/CodeNarc/src/main/resources/rulesets/ecocode.xml index 5c10668ee..8c8bc7514 100644 --- a/src/codenarc-converter/CodeNarc/src/main/resources/rulesets/ecocode.xml +++ b/src/codenarc-converter/CodeNarc/src/main/resources/rulesets/ecocode.xml @@ -9,4 +9,5 @@ + diff --git a/src/codenarc-converter/CodeNarc/src/test/groovy/org/codenarc/rule/ecocode/DisableObfuscationRuleTest.groovy b/src/codenarc-converter/CodeNarc/src/test/groovy/org/codenarc/rule/ecocode/DisableObfuscationRuleTest.groovy new file mode 100644 index 000000000..2b39dbd36 --- /dev/null +++ b/src/codenarc-converter/CodeNarc/src/test/groovy/org/codenarc/rule/ecocode/DisableObfuscationRuleTest.groovy @@ -0,0 +1,217 @@ +/* + * Copyright 2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.codenarc.rule.ecocode + +import org.junit.Test +import org.codenarc.rule.AbstractRuleTestCase + +/** + * Tests for DisableObfuscationRule + * + * @author Leboulanger Mickael + */ +class DisableObfuscationRuleTest extends AbstractRuleTestCase { + + @Test + void test_RuleProperties() { + assert rule.priority == 2 + assert rule.name == 'DisableObfuscation' + } + + @Test + void test_SomeCondition_NoViolations() { + final SOURCE = ''' + android { + compileSdk 32 + + defaultConfig { + applicationId "com.example.sampleForSonar" + minSdkVersion 28 + targetSdkVersion 32 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro\' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + buildFeatures { + viewBinding true + } + } + ''' + assertNoViolations(SOURCE) + } + + @Test + void testDetect_minifyEnabled_true() { + final SOURCE = ''' + android { + compileSdk 32 + + defaultConfig { + applicationId "com.example.sampleForSonar" + minSdkVersionVersionVersion 28 + targetSdkVersionVersionVersion 32 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled true + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro\' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + buildFeatures { + viewBinding true + } + } + ''' + assertSingleViolation(SOURCE, 17, 'minifyEnabled', getViolationMessage()) + } + + @Test + void testDetect_minifyEnabled_variable_true_before() { + final SOURCE = ''' + def minify = true + android { + compileSdk 32 + + defaultConfig { + applicationId "com.example.sampleForSonar" + minSdkVersionVersion 28 + targetSdkVersionVersion 32 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled minify + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro\' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + buildFeatures { + viewBinding true + } + } + ''' + assertSingleViolation(SOURCE, 18, 'minifyEnabled', getViolationMessage()) + } + + @Test + void testDetect_multiDexEnabled_variable_true_after() { + final SOURCE = ''' + android { + compileSdk 32 + + defaultConfig { + applicationId "com.example.sampleForSonar" + minSdkVersion 28 + targetSdkVersion 32 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled minify + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro\' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + buildFeatures { + viewBinding true + } + } + def minify = true + ''' + assertSingleViolation(SOURCE, 17, 'minifyEnabled', getViolationMessage()) + } + + @Test + void testDetect_minifyEnabled_variable_may_be_true() { + final SOURCE = ''' + def minify = false + android { + compileSdk 32 + + defaultConfig { + applicationId "com.example.sampleForSonar" + minSdkVersion 28 + targetSdkVersion 32 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled minify + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro\' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + buildFeatures { + viewBinding true + } + } + if (true) { + minify = true + } + ''' + assertSingleViolation(SOURCE, 18, 'minifyEnabled', getViolationMessage()) + } + + @Override + protected DisableObfuscationRule createRule() { + new DisableObfuscationRule() + } + private String getViolationMessage() { + return 'Using minifyEnabled true will obfuscate code and will have a sligthly negative impact on power consumption at runtime.' + } +} From 3a9a8bdc88b120d01f80c64b93aa52e27b3ab794 Mon Sep 17 00:00:00 2001 From: Romain DUCASSE Date: Fri, 3 Jun 2022 11:47:22 +0200 Subject: [PATCH 031/119] Add rule for string buffer/builder initialization #GRSP0032-JAVA --- .../main/java/fr/cnumr/java/RulesList.java | 3 +- .../InitializeBufferWithAppropriateSize.java | 37 +++++++++++++++++++ .../cnumr/l10n/java/rules/java/GRSP0032.html | 18 +++++++++ .../cnumr/l10n/java/rules/java/GRSP0032.json | 13 +++++++ .../InitializeBufferWithAppropriateSize.java | 31 ++++++++++++++++ .../java/MyJavaFileCheckRegistrarTest.java | 2 +- ...itializeBufferWithAppropriateSizeTest.java | 16 ++++++++ 7 files changed, 118 insertions(+), 2 deletions(-) create mode 100644 src/java-plugin/src/main/java/fr/cnumr/java/checks/InitializeBufferWithAppropriateSize.java create mode 100644 src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRSP0032.html create mode 100644 src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRSP0032.json create mode 100644 src/java-plugin/src/test/files/InitializeBufferWithAppropriateSize.java create mode 100644 src/java-plugin/src/test/java/fr/cnumr/java/checks/InitializeBufferWithAppropriateSizeTest.java diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java b/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java index 7bcd53578..ad37dc770 100644 --- a/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java +++ b/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java @@ -46,7 +46,8 @@ public static List> getJavaChecks() { AvoidSQLRequestInLoop.class, AvoidFullSQLRequest.class, UseCorrectForLoop.class, - UnnecessarilyAssignValuesToVariables.class + UnnecessarilyAssignValuesToVariables.class, + InitializeBufferWithAppropriateSize.class )); } diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/checks/InitializeBufferWithAppropriateSize.java b/src/java-plugin/src/main/java/fr/cnumr/java/checks/InitializeBufferWithAppropriateSize.java new file mode 100644 index 000000000..01d9e1df0 --- /dev/null +++ b/src/java-plugin/src/main/java/fr/cnumr/java/checks/InitializeBufferWithAppropriateSize.java @@ -0,0 +1,37 @@ +package fr.cnumr.java.checks; + +import org.sonar.check.Priority; +import org.sonar.check.Rule; +import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; +import org.sonar.plugins.java.api.tree.NewClassTree; +import org.sonar.plugins.java.api.tree.Tree; +import org.sonar.plugins.java.api.tree.Tree.Kind; + +import java.util.Collections; +import java.util.List; + +@Rule( + key = "GRSP0032", + name = "Developpement", + description = InitializeBufferWithAppropriateSize.RULE_MESSAGE, + priority = Priority.MINOR, + tags = {"bug"}) +public class InitializeBufferWithAppropriateSize extends IssuableSubscriptionVisitor { + + protected static final String RULE_MESSAGE = "Initialize StringBuilder or StringBuffer with appropriate size"; + + @Override + public List nodesToVisit() { + return Collections.singletonList(Kind.NEW_CLASS); + } + + @Override + public void visitNode(Tree tree) { + NewClassTree newClassTree = (NewClassTree) tree; + if ((newClassTree.symbolType().is("java.lang.StringBuffer") + || newClassTree.symbolType().is("java.lang.StringBuilder")) + && newClassTree.arguments().isEmpty()) { + reportIssue(tree, RULE_MESSAGE); + } + } +} \ No newline at end of file diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRSP0032.html b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRSP0032.html new file mode 100644 index 000000000..f4ae02219 --- /dev/null +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRSP0032.html @@ -0,0 +1,18 @@ +

+ If you know in advance how many characters would be appended, initialize builder/buffer with the appropriate size. + They will thus never have to be resized. +

+

Noncompliant Code Example

+
+    StringBuilder sb = new StringBuilder(); // Noncompliant
+    for (int i = 0; i < 100; i++) {
+       sb.append(...);
+    }
+
+

Compliant Solution

+
+    StringBuilder sb = new StringBuilder(100);
+    for (int i = 0; i < 100; i++) {
+       sb.append(...);
+    }
+
diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRSP0032.json b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRSP0032.json new file mode 100644 index 000000000..b51e2b3c6 --- /dev/null +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRSP0032.json @@ -0,0 +1,13 @@ +{ + "title": "Initialize builder/buffer with the appropriate size", + "type": "CODE_SMELL", + "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "5min" + }, + "tags": [ + "eco-conception" + ], + "defaultSeverity": "Minor" +} \ No newline at end of file diff --git a/src/java-plugin/src/test/files/InitializeBufferWithAppropriateSize.java b/src/java-plugin/src/test/files/InitializeBufferWithAppropriateSize.java new file mode 100644 index 000000000..664575af0 --- /dev/null +++ b/src/java-plugin/src/test/files/InitializeBufferWithAppropriateSize.java @@ -0,0 +1,31 @@ +package fr.cnumr.java.checks; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.Statement; + +class InitializeBufferWithAppropriateSize { + InitializeBufferWithAppropriateSize(InitializeBufferWithAppropriateSize mc) { + } + + public void testBufferCompliant() { + StringBuffer stringBuffer = new StringBuffer(16); + } + + public void testBufferCompliant2() { + StringBuffer stringBuffer = new StringBuffer(Integer.valueOf(16)); + } + + public void testBufferNonCompliant() { + StringBuffer stringBuffer = new StringBuffer(); // Noncompliant + } + + public void testBuilderCompliant() { + StringBuilder stringBuilder = new StringBuilder(16); + } + + public void testBuilderNonCompliant() { + StringBuilder stringBuilder = new StringBuilder(); // Noncompliant + } +} \ No newline at end of file diff --git a/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java b/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java index bbc12316c..81ad838e2 100644 --- a/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java +++ b/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java @@ -32,7 +32,7 @@ void checkNumberRules() { MyJavaFileCheckRegistrar registrar = new MyJavaFileCheckRegistrar(); registrar.register(context); - assertThat(context.checkClasses()).hasSize(6); + assertThat(context.checkClasses()).hasSize(7); assertThat(context.testCheckClasses()).isEmpty(); } diff --git a/src/java-plugin/src/test/java/fr/cnumr/java/checks/InitializeBufferWithAppropriateSizeTest.java b/src/java-plugin/src/test/java/fr/cnumr/java/checks/InitializeBufferWithAppropriateSizeTest.java new file mode 100644 index 000000000..134b6c5ef --- /dev/null +++ b/src/java-plugin/src/test/java/fr/cnumr/java/checks/InitializeBufferWithAppropriateSizeTest.java @@ -0,0 +1,16 @@ +package fr.cnumr.java.checks; + +import org.junit.jupiter.api.Test; +import org.sonar.java.checks.verifier.JavaCheckVerifier; + +class InitializeBufferWithAppropriateSizeTest { + + @Test + void test() { + JavaCheckVerifier.newVerifier() + .onFile("src/test/files/InitializeBufferWithAppropriateSize.java") + .withCheck(new InitializeBufferWithAppropriateSize()) + .verifyIssues(); + } + +} \ No newline at end of file From be437a3fb49d1c92af0525aa0260a0bfe3d54f1e Mon Sep 17 00:00:00 2001 From: MP-Aubay Date: Thu, 16 Jun 2022 11:44:24 +0200 Subject: [PATCH 032/119] GRC1 - Calling Spring repository in loops (#117) --- docs/rules/web-matrix.md | 3 +- src/java-plugin/pom.xml | 21 ++++++-- .../main/java/fr/cnumr/java/RulesList.java | 1 + .../AvoidSpringRepositoryCallInLoopCheck.java | 51 +++++++++++++++++++ .../fr/cnumr/l10n/java/rules/java/GRC1.html | 21 ++++++++ .../fr/cnumr/l10n/java/rules/java/GRC1.json | 13 +++++ .../AvoidSpringRepositoryCallInLoopCheck.java | 30 +++++++++++ .../java/MyJavaFileCheckRegistrarTest.java | 2 +- ...idSpringRepositoryCallInLoopCheckTest.java | 19 +++++++ 9 files changed, 155 insertions(+), 6 deletions(-) create mode 100644 src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidSpringRepositoryCallInLoopCheck.java create mode 100644 src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRC1.html create mode 100644 src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRC1.json create mode 100644 src/java-plugin/src/test/files/AvoidSpringRepositoryCallInLoopCheck.java create mode 100644 src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidSpringRepositoryCallInLoopCheckTest.java diff --git a/docs/rules/web-matrix.md b/docs/rules/web-matrix.md index b5b5009ce..5a9a3f781 100644 --- a/docs/rules/web-matrix.md +++ b/docs/rules/web-matrix.md @@ -35,4 +35,5 @@ Here is the list of rules already available in ecoCode project code. | Use the $i++ variable during an iteration | ✅ | ✅ | | | | | | Calling a function in the declaration of a for loop | ✅ | ✅ | | ✅ | | | | Perform an SQL query inside a loop | ✅ | ✅ | | | | | -| Write SELECT * FROM | ✅ | ✅ | | ✅ | | | \ No newline at end of file +| Write SELECT * FROM | ✅ | ✅ | | ✅ | | | +| Calling a Spring repository inside a loop | ✅ | 🚫 | 🚫 | 🚫 | 🚫 | 🚫 | \ No newline at end of file diff --git a/src/java-plugin/pom.xml b/src/java-plugin/pom.xml index b391b0899..02007682d 100644 --- a/src/java-plugin/pom.xml +++ b/src/java-plugin/pom.xml @@ -59,6 +59,7 @@ org.assertj assertj-core + @@ -87,7 +88,7 @@ copy-bundle package - copy + copy @@ -169,21 +170,33 @@ org.springframework spring-webmvc - 4.3.3.RELEASE + 5.2.3.RELEASE jar org.springframework spring-web - 4.3.3.RELEASE + 5.2.3.RELEASE jar org.springframework spring-context - 4.3.3.RELEASE + 5.2.3.RELEASE jar + + org.springframework.data + spring-data-jpa + 2.2.4.RELEASE + jar + + + org.springframework.data + spring-data-commons + 2.2.4.RELEASE + jar + ${project.build.directory}/test-jars diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java b/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java index 7bcd53578..bebf41b05 100644 --- a/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java +++ b/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java @@ -43,6 +43,7 @@ public static List> getJavaChecks() { return Collections.unmodifiableList(Arrays.asList( IncrementCheck.class, NoFunctionCallWhenDeclaringForLoop.class, + AvoidSpringRepositoryCallInLoopCheck.class, AvoidSQLRequestInLoop.class, AvoidFullSQLRequest.class, UseCorrectForLoop.class, diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidSpringRepositoryCallInLoopCheck.java b/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidSpringRepositoryCallInLoopCheck.java new file mode 100644 index 000000000..f0eb5b8dd --- /dev/null +++ b/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidSpringRepositoryCallInLoopCheck.java @@ -0,0 +1,51 @@ +package fr.cnumr.java.checks; + +import java.util.Arrays; +import java.util.List; + +import org.sonar.check.Priority; +import org.sonar.check.Rule; +import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; +import org.sonar.plugins.java.api.semantic.MethodMatchers; +import org.sonar.plugins.java.api.tree.BaseTreeVisitor; +import org.sonar.plugins.java.api.tree.MethodInvocationTree; +import org.sonar.plugins.java.api.tree.Tree; + +@Rule(key = "GRC1", + name = "Developpement", + description = AvoidSpringRepositoryCallInLoopCheck.RULE_MESSAGE, + priority = Priority.MINOR, + tags = {"bug" }) +public class AvoidSpringRepositoryCallInLoopCheck extends IssuableSubscriptionVisitor { + + protected static final String RULE_MESSAGE = "Avoid Spring repository call in loop"; + + private static final String SPRING_REPOSITORY = "org.springframework.data.repository.Repository"; + + private static final MethodMatchers REPOSITORY_METHOD = + MethodMatchers.create().ofSubTypes(SPRING_REPOSITORY).anyName().withAnyParameters() + .build(); + + private final AvoidSpringRepositoryCallInLoopCheckVisitor visitorInFile = new AvoidSpringRepositoryCallInLoopCheckVisitor(); + + @Override + public List nodesToVisit() { + return Arrays.asList(Tree.Kind.FOR_EACH_STATEMENT, Tree.Kind.FOR_STATEMENT, Tree.Kind.WHILE_STATEMENT); + } + + @Override + public void visitNode(Tree tree) { + tree.accept(visitorInFile); + } + + private class AvoidSpringRepositoryCallInLoopCheckVisitor extends BaseTreeVisitor { + @Override + public void visitMethodInvocation(MethodInvocationTree tree) { + if (REPOSITORY_METHOD.matches(tree)) { + reportIssue(tree, RULE_MESSAGE); + } else { + super.visitMethodInvocation(tree); + } + } + } +} diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRC1.html b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRC1.html new file mode 100644 index 000000000..9b81f5b10 --- /dev/null +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRC1.html @@ -0,0 +1,21 @@ +

Avoid Spring repository call in loop

+

Noncompliant Code Example

+
+		private final List ids = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
+
+		List employees = new ArrayList<>();
+		
+		for (Integer id: ids) {
+            Optional employee = employeeRepository.findById(id); // Noncompliant {{Avoid Spring repository call in loop}}
+            if (employee.isPresent()) {
+                employees.add(employee.get());
+            }
+        }
+
+
+

Compliant Solution

+
+		private final List ids = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
+		
+		List employees = employeeRepository.findAllById(ids);
+
diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRC1.json b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRC1.json new file mode 100644 index 000000000..5991d83ec --- /dev/null +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRC1.json @@ -0,0 +1,13 @@ +{ + "title": "Avoid Spring repository call in loop", + "type": "CODE_SMELL", + "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "50min" + }, + "tags": [ + "eco-conception" + ], + "defaultSeverity": "Minor" +} \ No newline at end of file diff --git a/src/java-plugin/src/test/files/AvoidSpringRepositoryCallInLoopCheck.java b/src/java-plugin/src/test/files/AvoidSpringRepositoryCallInLoopCheck.java new file mode 100644 index 000000000..1b3527bb7 --- /dev/null +++ b/src/java-plugin/src/test/files/AvoidSpringRepositoryCallInLoopCheck.java @@ -0,0 +1,30 @@ +package fr.cnumr.java.checks; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.*; +import java.util.stream.Collectors; + +public class AvoidRepositoryCallInLoopCheck { + @Autowired + private EmployeeRepository employeeRepository; + + public List smellGetAllEmployeesByIds(List ids){ + List employees = new ArrayList<>(); + for (Integer id: ids) { + Optional employee = employeeRepository.findById(id); // Noncompliant {{Avoid Spring repository call in loop}} + if (employee.isPresent()) { + employees.add(employee.get()); + } + } + return employees; + } + + public class Employee {} + + public interface EmployeeRepository extends JpaRepository{ + + } + +} \ No newline at end of file diff --git a/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java b/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java index bbc12316c..81ad838e2 100644 --- a/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java +++ b/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java @@ -32,7 +32,7 @@ void checkNumberRules() { MyJavaFileCheckRegistrar registrar = new MyJavaFileCheckRegistrar(); registrar.register(context); - assertThat(context.checkClasses()).hasSize(6); + assertThat(context.checkClasses()).hasSize(7); assertThat(context.testCheckClasses()).isEmpty(); } diff --git a/src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidSpringRepositoryCallInLoopCheckTest.java b/src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidSpringRepositoryCallInLoopCheckTest.java new file mode 100644 index 000000000..d3a5c30e5 --- /dev/null +++ b/src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidSpringRepositoryCallInLoopCheckTest.java @@ -0,0 +1,19 @@ +package fr.cnumr.java.checks; + +import org.junit.jupiter.api.Test; +import org.sonar.java.checks.verifier.CheckVerifier; + +import fr.cnumr.java.utils.FilesUtils; + +public class AvoidSpringRepositoryCallInLoopCheckTest { + + @Test + void test() { + CheckVerifier.newVerifier() + .onFile("src/test/files/AvoidSpringRepositoryCallInLoopCheck.java") + .withCheck(new AvoidSpringRepositoryCallInLoopCheck()) + .withClassPath(FilesUtils.getClassPath("target/test-jars")) + .verifyIssues(); + } + +} From 63bc5d6373813b9fae9b4d6c0633ffbd121fb465 Mon Sep 17 00:00:00 2001 From: Jules Delecour Date: Fri, 17 Jun 2022 11:42:06 +0200 Subject: [PATCH 033/119] fixing tag eco-conception to ecocode --- .../src/main/resources/fr/cnumr/l10n/java/rules/java/GRC1.json | 2 +- .../src/main/resources/fr/cnumr/l10n/java/rules/java/S53.json | 2 +- .../src/main/resources/fr/cnumr/l10n/java/rules/java/S63.json | 2 +- .../src/main/resources/fr/cnumr/l10n/java/rules/java/S67.json | 2 +- .../src/main/resources/fr/cnumr/l10n/java/rules/java/S69.json | 2 +- .../src/main/resources/fr/cnumr/l10n/java/rules/java/S72.json | 2 +- .../src/main/resources/fr/cnumr/l10n/java/rules/java/S74.json | 2 +- .../src/main/resources/fr/cnumr/l10n/php/rules/custom/S34.json | 2 +- .../src/main/resources/fr/cnumr/l10n/php/rules/custom/S66.json | 2 +- .../src/main/resources/fr/cnumr/l10n/php/rules/custom/S67.json | 2 +- .../src/main/resources/fr/cnumr/l10n/php/rules/custom/S69.json | 2 +- .../src/main/resources/fr/cnumr/l10n/php/rules/custom/S72.json | 2 +- .../src/main/resources/fr/cnumr/l10n/php/rules/custom/S74.json | 2 +- .../main/resources/fr/cnumr/l10n/python/rules/python/S34.json | 2 +- .../main/resources/fr/cnumr/l10n/python/rules/python/S66.json | 2 +- .../main/resources/fr/cnumr/l10n/python/rules/python/S69.json | 2 +- .../main/resources/fr/cnumr/l10n/python/rules/python/S74.json | 2 +- 17 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRC1.json b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRC1.json index 5991d83ec..95ed2e54d 100644 --- a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRC1.json +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRC1.json @@ -7,7 +7,7 @@ "constantCost": "50min" }, "tags": [ - "eco-conception" + "ecocode" ], "defaultSeverity": "Minor" } \ No newline at end of file diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S53.json b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S53.json index ff78ee1be..a666eb11a 100644 --- a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S53.json +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S53.json @@ -7,7 +7,7 @@ "constantCost": "5min" }, "tags": [ - "eco-conception" + "ecocode" ], "defaultSeverity": "Minor" } \ No newline at end of file diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S63.json b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S63.json index bc29be46b..c56e5a649 100644 --- a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S63.json +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S63.json @@ -7,7 +7,7 @@ "constantCost": "5min" }, "tags": [ - "eco-conception" + "ecocode" ], "defaultSeverity": "Minor" } \ No newline at end of file diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S67.json b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S67.json index c6b6e9b09..ec02eda10 100644 --- a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S67.json +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S67.json @@ -7,7 +7,7 @@ "constantCost": "5min" }, "tags": [ - "eco-conception" + "ecocode" ], "defaultSeverity": "Minor" } \ No newline at end of file diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S69.json b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S69.json index d51cbccf7..4d7785f65 100644 --- a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S69.json +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S69.json @@ -7,7 +7,7 @@ "constantCost": "5min" }, "tags": [ - "eco-conception" + "ecocode" ], "defaultSeverity": "Minor" } \ No newline at end of file diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S72.json b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S72.json index 73743a5a5..ec95852ce 100644 --- a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S72.json +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S72.json @@ -7,7 +7,7 @@ "constantCost": "10min" }, "tags": [ - "eco-conception" + "ecocode" ], "defaultSeverity": "Minor" } \ No newline at end of file diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S74.json b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S74.json index f561e6a84..b19da3c57 100644 --- a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S74.json +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S74.json @@ -7,7 +7,7 @@ "constantCost": "20min" }, "tags": [ - "eco-conception" + "ecocode" ], "defaultSeverity": "Minor" } \ No newline at end of file diff --git a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S34.json b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S34.json index 72a37f621..05a6db7cf 100644 --- a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S34.json +++ b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S34.json @@ -7,7 +7,7 @@ "constantCost": "5min" }, "tags": [ - "eco-conception" + "ecocode" ], "defaultSeverity": "Minor" } \ No newline at end of file diff --git a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S66.json b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S66.json index 55464b52c..487ca6e41 100644 --- a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S66.json +++ b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S66.json @@ -7,7 +7,7 @@ "constantCost": "5min" }, "tags": [ - "eco-conception" + "ecocode" ], "defaultSeverity": "Minor" } \ No newline at end of file diff --git a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S67.json b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S67.json index 2934198d6..074c72d5d 100644 --- a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S67.json +++ b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S67.json @@ -7,7 +7,7 @@ "constantCost": "5min" }, "tags": [ - "eco-conception" + "ecocode" ], "defaultSeverity": "Minor" } \ No newline at end of file diff --git a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S69.json b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S69.json index 68cabdd39..1bd29a466 100644 --- a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S69.json +++ b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S69.json @@ -7,7 +7,7 @@ "constantCost": "5min" }, "tags": [ - "eco-conception" + "ecocode" ], "defaultSeverity": "Minor" } \ No newline at end of file diff --git a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S72.json b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S72.json index 73743a5a5..ec95852ce 100644 --- a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S72.json +++ b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S72.json @@ -7,7 +7,7 @@ "constantCost": "10min" }, "tags": [ - "eco-conception" + "ecocode" ], "defaultSeverity": "Minor" } \ No newline at end of file diff --git a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S74.json b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S74.json index f561e6a84..b19da3c57 100644 --- a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S74.json +++ b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S74.json @@ -7,7 +7,7 @@ "constantCost": "20min" }, "tags": [ - "eco-conception" + "ecocode" ], "defaultSeverity": "Minor" } \ No newline at end of file diff --git a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S34.json b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S34.json index e3718d9f9..03e92cc86 100644 --- a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S34.json +++ b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S34.json @@ -7,7 +7,7 @@ "constantCost": "5min" }, "tags": [ - "eco-conception" + "ecocode" ], "defaultSeverity": "Minor" } \ No newline at end of file diff --git a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S66.json b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S66.json index 1fd95da11..6ccc84e55 100644 --- a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S66.json +++ b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S66.json @@ -7,7 +7,7 @@ "constantCost": "5min" }, "tags": [ - "eco-conception" + "ecocode" ], "defaultSeverity": "Minor" } \ No newline at end of file diff --git a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S69.json b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S69.json index e3718d9f9..03e92cc86 100644 --- a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S69.json +++ b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S69.json @@ -7,7 +7,7 @@ "constantCost": "5min" }, "tags": [ - "eco-conception" + "ecocode" ], "defaultSeverity": "Minor" } \ No newline at end of file diff --git a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S74.json b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S74.json index f561e6a84..b19da3c57 100644 --- a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S74.json +++ b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S74.json @@ -7,7 +7,7 @@ "constantCost": "20min" }, "tags": [ - "eco-conception" + "ecocode" ], "defaultSeverity": "Minor" } \ No newline at end of file From 9abebd0e74929fe83e20b5d33f0f99c121f6587a Mon Sep 17 00:00:00 2001 From: Jules Delecour Date: Fri, 17 Jun 2022 11:55:18 +0200 Subject: [PATCH 034/119] Revert "fixing tag eco-conception to ecocode" This reverts commit 63bc5d6373813b9fae9b4d6c0633ffbd121fb465. --- .../src/main/resources/fr/cnumr/l10n/java/rules/java/GRC1.json | 2 +- .../src/main/resources/fr/cnumr/l10n/java/rules/java/S53.json | 2 +- .../src/main/resources/fr/cnumr/l10n/java/rules/java/S63.json | 2 +- .../src/main/resources/fr/cnumr/l10n/java/rules/java/S67.json | 2 +- .../src/main/resources/fr/cnumr/l10n/java/rules/java/S69.json | 2 +- .../src/main/resources/fr/cnumr/l10n/java/rules/java/S72.json | 2 +- .../src/main/resources/fr/cnumr/l10n/java/rules/java/S74.json | 2 +- .../src/main/resources/fr/cnumr/l10n/php/rules/custom/S34.json | 2 +- .../src/main/resources/fr/cnumr/l10n/php/rules/custom/S66.json | 2 +- .../src/main/resources/fr/cnumr/l10n/php/rules/custom/S67.json | 2 +- .../src/main/resources/fr/cnumr/l10n/php/rules/custom/S69.json | 2 +- .../src/main/resources/fr/cnumr/l10n/php/rules/custom/S72.json | 2 +- .../src/main/resources/fr/cnumr/l10n/php/rules/custom/S74.json | 2 +- .../main/resources/fr/cnumr/l10n/python/rules/python/S34.json | 2 +- .../main/resources/fr/cnumr/l10n/python/rules/python/S66.json | 2 +- .../main/resources/fr/cnumr/l10n/python/rules/python/S69.json | 2 +- .../main/resources/fr/cnumr/l10n/python/rules/python/S74.json | 2 +- 17 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRC1.json b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRC1.json index 95ed2e54d..5991d83ec 100644 --- a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRC1.json +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRC1.json @@ -7,7 +7,7 @@ "constantCost": "50min" }, "tags": [ - "ecocode" + "eco-conception" ], "defaultSeverity": "Minor" } \ No newline at end of file diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S53.json b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S53.json index a666eb11a..ff78ee1be 100644 --- a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S53.json +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S53.json @@ -7,7 +7,7 @@ "constantCost": "5min" }, "tags": [ - "ecocode" + "eco-conception" ], "defaultSeverity": "Minor" } \ No newline at end of file diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S63.json b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S63.json index c56e5a649..bc29be46b 100644 --- a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S63.json +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S63.json @@ -7,7 +7,7 @@ "constantCost": "5min" }, "tags": [ - "ecocode" + "eco-conception" ], "defaultSeverity": "Minor" } \ No newline at end of file diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S67.json b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S67.json index ec02eda10..c6b6e9b09 100644 --- a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S67.json +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S67.json @@ -7,7 +7,7 @@ "constantCost": "5min" }, "tags": [ - "ecocode" + "eco-conception" ], "defaultSeverity": "Minor" } \ No newline at end of file diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S69.json b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S69.json index 4d7785f65..d51cbccf7 100644 --- a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S69.json +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S69.json @@ -7,7 +7,7 @@ "constantCost": "5min" }, "tags": [ - "ecocode" + "eco-conception" ], "defaultSeverity": "Minor" } \ No newline at end of file diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S72.json b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S72.json index ec95852ce..73743a5a5 100644 --- a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S72.json +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S72.json @@ -7,7 +7,7 @@ "constantCost": "10min" }, "tags": [ - "ecocode" + "eco-conception" ], "defaultSeverity": "Minor" } \ No newline at end of file diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S74.json b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S74.json index b19da3c57..f561e6a84 100644 --- a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S74.json +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S74.json @@ -7,7 +7,7 @@ "constantCost": "20min" }, "tags": [ - "ecocode" + "eco-conception" ], "defaultSeverity": "Minor" } \ No newline at end of file diff --git a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S34.json b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S34.json index 05a6db7cf..72a37f621 100644 --- a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S34.json +++ b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S34.json @@ -7,7 +7,7 @@ "constantCost": "5min" }, "tags": [ - "ecocode" + "eco-conception" ], "defaultSeverity": "Minor" } \ No newline at end of file diff --git a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S66.json b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S66.json index 487ca6e41..55464b52c 100644 --- a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S66.json +++ b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S66.json @@ -7,7 +7,7 @@ "constantCost": "5min" }, "tags": [ - "ecocode" + "eco-conception" ], "defaultSeverity": "Minor" } \ No newline at end of file diff --git a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S67.json b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S67.json index 074c72d5d..2934198d6 100644 --- a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S67.json +++ b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S67.json @@ -7,7 +7,7 @@ "constantCost": "5min" }, "tags": [ - "ecocode" + "eco-conception" ], "defaultSeverity": "Minor" } \ No newline at end of file diff --git a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S69.json b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S69.json index 1bd29a466..68cabdd39 100644 --- a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S69.json +++ b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S69.json @@ -7,7 +7,7 @@ "constantCost": "5min" }, "tags": [ - "ecocode" + "eco-conception" ], "defaultSeverity": "Minor" } \ No newline at end of file diff --git a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S72.json b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S72.json index ec95852ce..73743a5a5 100644 --- a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S72.json +++ b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S72.json @@ -7,7 +7,7 @@ "constantCost": "10min" }, "tags": [ - "ecocode" + "eco-conception" ], "defaultSeverity": "Minor" } \ No newline at end of file diff --git a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S74.json b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S74.json index b19da3c57..f561e6a84 100644 --- a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S74.json +++ b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S74.json @@ -7,7 +7,7 @@ "constantCost": "20min" }, "tags": [ - "ecocode" + "eco-conception" ], "defaultSeverity": "Minor" } \ No newline at end of file diff --git a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S34.json b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S34.json index 03e92cc86..e3718d9f9 100644 --- a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S34.json +++ b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S34.json @@ -7,7 +7,7 @@ "constantCost": "5min" }, "tags": [ - "ecocode" + "eco-conception" ], "defaultSeverity": "Minor" } \ No newline at end of file diff --git a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S66.json b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S66.json index 6ccc84e55..1fd95da11 100644 --- a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S66.json +++ b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S66.json @@ -7,7 +7,7 @@ "constantCost": "5min" }, "tags": [ - "ecocode" + "eco-conception" ], "defaultSeverity": "Minor" } \ No newline at end of file diff --git a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S69.json b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S69.json index 03e92cc86..e3718d9f9 100644 --- a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S69.json +++ b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S69.json @@ -7,7 +7,7 @@ "constantCost": "5min" }, "tags": [ - "ecocode" + "eco-conception" ], "defaultSeverity": "Minor" } \ No newline at end of file diff --git a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S74.json b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S74.json index b19da3c57..f561e6a84 100644 --- a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S74.json +++ b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S74.json @@ -7,7 +7,7 @@ "constantCost": "20min" }, "tags": [ - "ecocode" + "eco-conception" ], "defaultSeverity": "Minor" } \ No newline at end of file From 4430ebde46b055458796a5aa5cc9fd4745cebd83 Mon Sep 17 00:00:00 2001 From: rcollin Date: Fri, 17 Jun 2022 12:04:11 +0200 Subject: [PATCH 035/119] 99 rule (#136) * 99 rule * Update S99.html Co-authored-by: Jules Delecour <72793427+jules-delecour-dav@users.noreply.github.com> --- src/xml-plugin/README.md | 1 + src/xml-plugin/pom.xml | 102 +++++++ .../main/java/fr/cnumr/xml/MyXmlRules.java | 55 ++++ .../fr/cnumr/xml/XMLCustomRulesPlugin.java | 33 +++ .../java/fr/cnumr/xml/checks/CheckList.java | 34 +++ .../xml/checks/UseUnoptimizedVectorImage.java | 37 +++ .../fr/cnumr/l10n/xml/rules/custom/S99.html | 11 + .../fr/cnumr/l10n/xml/rules/custom/S99.json | 13 + .../java/fr/cnumr/xml/MyXmlRulesTest.java | 20 ++ .../checks/UseUnoptimizedVectorImageTest.java | 28 ++ .../UseUnoptimizedVectorImage.svg | 56 ++++ .../UseUnoptimizedVectorImageSVGO.svg | 1 + .../checks/UseUnoptimizedVectorImage/pom.xml | 265 ++++++++++++++++++ 13 files changed, 656 insertions(+) create mode 100644 src/xml-plugin/README.md create mode 100644 src/xml-plugin/pom.xml create mode 100644 src/xml-plugin/src/main/java/fr/cnumr/xml/MyXmlRules.java create mode 100644 src/xml-plugin/src/main/java/fr/cnumr/xml/XMLCustomRulesPlugin.java create mode 100644 src/xml-plugin/src/main/java/fr/cnumr/xml/checks/CheckList.java create mode 100644 src/xml-plugin/src/main/java/fr/cnumr/xml/checks/UseUnoptimizedVectorImage.java create mode 100644 src/xml-plugin/src/main/resources/fr/cnumr/l10n/xml/rules/custom/S99.html create mode 100644 src/xml-plugin/src/main/resources/fr/cnumr/l10n/xml/rules/custom/S99.json create mode 100644 src/xml-plugin/src/test/java/fr/cnumr/xml/MyXmlRulesTest.java create mode 100644 src/xml-plugin/src/test/java/fr/cnumr/xml/checks/UseUnoptimizedVectorImageTest.java create mode 100644 src/xml-plugin/src/test/resources/checks/UseUnoptimizedVectorImage/UseUnoptimizedVectorImage.svg create mode 100644 src/xml-plugin/src/test/resources/checks/UseUnoptimizedVectorImage/UseUnoptimizedVectorImageSVGO.svg create mode 100644 src/xml-plugin/src/test/resources/checks/UseUnoptimizedVectorImage/pom.xml diff --git a/src/xml-plugin/README.md b/src/xml-plugin/README.md new file mode 100644 index 000000000..bbcc22d84 --- /dev/null +++ b/src/xml-plugin/README.md @@ -0,0 +1 @@ +https://github.com/SonarSource/sonar-custom-rules-examples/tree/master/xml-custom-rules \ No newline at end of file diff --git a/src/xml-plugin/pom.xml b/src/xml-plugin/pom.xml new file mode 100644 index 000000000..0d91c8804 --- /dev/null +++ b/src/xml-plugin/pom.xml @@ -0,0 +1,102 @@ + + + 4.0.0 + + fr.cnumr + ecocode + 1.0.0-SNAPSHOT + + + ecocode-xml-plugin + sonar-plugin + ecoCode XML Sonar Plugin + + + + + + org.sonarsource.sonarqube + sonar-plugin-api + + + + org.sonarsource.xml + sonar-xml-plugin + sonar-plugin + 2.5.0.3376 + + + + org.sonarsource.analyzer-commons + sonar-xml-parsing + 1.25.0.1003 + + + + junit + junit + + + + org.sonarsource.analyzer-commons + test-sonar-xml-parsing + 1.25.0.1003 + test + + + + + + + org.sonarsource.sonar-packaging-maven-plugin + sonar-packaging-maven-plugin + ${sonar-packaging.version} + true + + ${project.artifactId} + ${project.name} + fr.cnumr.xml.XMLCustomRulesPlugin + true + 6.7 + xml + + + + org.apache.maven.plugins + maven-dependency-plugin + + + copy-bundle + package + + copy + + + + + ${project.groupId} + ${project.artifactId} + ${project.version} + jar + true + + + ../lib + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.6.0 + + 1.8 + 1.8 + + + + + + diff --git a/src/xml-plugin/src/main/java/fr/cnumr/xml/MyXmlRules.java b/src/xml-plugin/src/main/java/fr/cnumr/xml/MyXmlRules.java new file mode 100644 index 000000000..e54090e06 --- /dev/null +++ b/src/xml-plugin/src/main/java/fr/cnumr/xml/MyXmlRules.java @@ -0,0 +1,55 @@ +/* + * SonarQube PHP Custom Rules Example + * Copyright (C) 2016-2016 SonarSource SA + * mailto:contact 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 fr.cnumr.xml; + +import java.util.Collections; +import java.util.Set; + +import org.sonar.api.server.rule.RulesDefinition; +import org.sonarsource.analyzer.commons.RuleMetadataLoader; + +import fr.cnumr.xml.checks.CheckList; + +/** + * Extension point to define a PHP rule repository. + */ +public class MyXmlRules implements RulesDefinition { + + public static final String LANGUAGE = "xml"; + public static final String NAME = "MyCompany Custom Repository"; + public static final String RESOURCE_BASE_PATH = "fr/cnumr/l10n/xml/rules/custom"; + public static final String REPOSITORY_KEY = "cnumr-xml"; + private static final Set RULE_TEMPLATES_KEY = Collections.emptySet(); + + @Override + public void define(Context context) { + NewRepository repository = context.createRepository(REPOSITORY_KEY, LANGUAGE).setName(NAME); + + RuleMetadataLoader ruleMetadataLoader = new RuleMetadataLoader(RESOURCE_BASE_PATH); + + // add the new checks + ruleMetadataLoader.addRulesByAnnotatedClass(repository, CheckList.getCheckClasses()); + +// repository.rule("XPathCheck").setTemplate(true); +// repository.rule("S3417").setTemplate(true); + repository.done(); + } + +} diff --git a/src/xml-plugin/src/main/java/fr/cnumr/xml/XMLCustomRulesPlugin.java b/src/xml-plugin/src/main/java/fr/cnumr/xml/XMLCustomRulesPlugin.java new file mode 100644 index 000000000..b3cd9d0d3 --- /dev/null +++ b/src/xml-plugin/src/main/java/fr/cnumr/xml/XMLCustomRulesPlugin.java @@ -0,0 +1,33 @@ +/* + * SonarQube PHP Custom Rules Example + * Copyright (C) 2016-2016 SonarSource SA + * mailto:contact 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 fr.cnumr.xml; + +import org.sonar.api.Plugin; + +/** + * Extension point to define a Sonar Plugin. + */ +public class XMLCustomRulesPlugin implements Plugin { + + @Override + public void define(Context context) { + context.addExtension(MyXmlRules.class); + } +} diff --git a/src/xml-plugin/src/main/java/fr/cnumr/xml/checks/CheckList.java b/src/xml-plugin/src/main/java/fr/cnumr/xml/checks/CheckList.java new file mode 100644 index 000000000..9f21859a4 --- /dev/null +++ b/src/xml-plugin/src/main/java/fr/cnumr/xml/checks/CheckList.java @@ -0,0 +1,34 @@ +/* + * SonarQube XML Plugin + * Copyright (C) 2010-2021 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 fr.cnumr.xml.checks; + +import java.util.Arrays; +import java.util.List; + +public class CheckList { + + private CheckList() { + } + + public static List> getCheckClasses() { + return Arrays.asList(UseUnoptimizedVectorImage.class); + } + +} diff --git a/src/xml-plugin/src/main/java/fr/cnumr/xml/checks/UseUnoptimizedVectorImage.java b/src/xml-plugin/src/main/java/fr/cnumr/xml/checks/UseUnoptimizedVectorImage.java new file mode 100644 index 000000000..01aa9360f --- /dev/null +++ b/src/xml-plugin/src/main/java/fr/cnumr/xml/checks/UseUnoptimizedVectorImage.java @@ -0,0 +1,37 @@ +package fr.cnumr.xml.checks; + +import java.util.Collections; + +import org.sonar.check.Priority; +import org.sonar.check.Rule; +import org.sonarsource.analyzer.commons.xml.XmlFile; +import org.sonarsource.analyzer.commons.xml.checks.SonarXmlCheck; + +@Rule(key = "S99", name = "Developpement", description = UseUnoptimizedVectorImage.MESSAGERULE, priority = Priority.MINOR, tags = { "bug" }) +public class UseUnoptimizedVectorImage extends SonarXmlCheck { + + protected static final String MESSAGERULE = "Avoid the use of unoptimized vector images"; + + private static final String PATTERN_METADATA = " "); + } + if (file.getContents().contains(PATTERN_TITLE)) { + nodesError = nodesError.append(" "); + } + if (file.getContents().contains(PATTERN_DESCRIPTION)) { + nodesError = nodesError.append("<desc> "); + + } + if (nodesError.length() > 0) { + reportIssueOnFile("Issue on node(s) " + nodesError.toString() + "of the vector image.", Collections.emptyList()); + } + } + +} \ No newline at end of file diff --git a/src/xml-plugin/src/main/resources/fr/cnumr/l10n/xml/rules/custom/S99.html b/src/xml-plugin/src/main/resources/fr/cnumr/l10n/xml/rules/custom/S99.html new file mode 100644 index 000000000..949989ca2 --- /dev/null +++ b/src/xml-plugin/src/main/resources/fr/cnumr/l10n/xml/rules/custom/S99.html @@ -0,0 +1,11 @@ +<p>Avoid the use of unoptimized vector images</p> +<h2>Noncompliant Code Example</h2> +<pre> +Votre image contient des métadata non nécessaires à la visualisation de l'image +Your image has metadatas that are not necessary to visualize it + +</pre> +<h2>Compliant Solution</h2> +<pre> +Use SVGO to scan your image +</pre> diff --git a/src/xml-plugin/src/main/resources/fr/cnumr/l10n/xml/rules/custom/S99.json b/src/xml-plugin/src/main/resources/fr/cnumr/l10n/xml/rules/custom/S99.json new file mode 100644 index 000000000..7f140a739 --- /dev/null +++ b/src/xml-plugin/src/main/resources/fr/cnumr/l10n/xml/rules/custom/S99.json @@ -0,0 +1,13 @@ +{ + "title": "Avoid the use of unoptimized vector images", + "type": "CODE_SMELL", + "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "5min" + }, + "tags": [ + "eco-conception" + ], + "defaultSeverity": "Minor" +} \ No newline at end of file diff --git a/src/xml-plugin/src/test/java/fr/cnumr/xml/MyXmlRulesTest.java b/src/xml-plugin/src/test/java/fr/cnumr/xml/MyXmlRulesTest.java new file mode 100644 index 000000000..49405b855 --- /dev/null +++ b/src/xml-plugin/src/test/java/fr/cnumr/xml/MyXmlRulesTest.java @@ -0,0 +1,20 @@ +package fr.cnumr.xml; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.sonar.api.server.rule.RulesDefinition; + +public class MyXmlRulesTest { + + private int NumberOfRuleInRepository = 6; + + @Test + public void rules() { + MyXmlRules rulesDefinition = new MyXmlRules(); + RulesDefinition.Context context = new RulesDefinition.Context(); + rulesDefinition.define(context); + RulesDefinition.Repository repository = context.repository(MyXmlRules.REPOSITORY_KEY); + assertEquals(NumberOfRuleInRepository, repository.rules().size()); + } +} diff --git a/src/xml-plugin/src/test/java/fr/cnumr/xml/checks/UseUnoptimizedVectorImageTest.java b/src/xml-plugin/src/test/java/fr/cnumr/xml/checks/UseUnoptimizedVectorImageTest.java new file mode 100644 index 000000000..36a5826d3 --- /dev/null +++ b/src/xml-plugin/src/test/java/fr/cnumr/xml/checks/UseUnoptimizedVectorImageTest.java @@ -0,0 +1,28 @@ +package fr.cnumr.xml.checks; + +import java.io.IOException; + +import org.junit.Test; +import org.sonarsource.analyzer.commons.xml.checks.SonarXmlCheckVerifier; + +public class UseUnoptimizedVectorImageTest { + + @Test + public void test() throws IOException { + UseUnoptimizedVectorImage check = new UseUnoptimizedVectorImage(); + SonarXmlCheckVerifier.verifyIssueOnFile("UseUnoptimizedVectorImage.svg", check, "Issue on node(s) <metadata> <title> <desc> of the vector image."); + } + + @Test + public void testSvgo() throws IOException { + UseUnoptimizedVectorImage check = new UseUnoptimizedVectorImage(); + SonarXmlCheckVerifier.verifyNoIssue("UseUnoptimizedVectorImageSVGO.svg", check); + } + + @Test + public void test3() throws IOException { + UseUnoptimizedVectorImage check = new UseUnoptimizedVectorImage(); + SonarXmlCheckVerifier.verifyIssueOnFile("pom.xml", check, "Issue on node(s) <title> <desc> of the vector image."); + } + +} \ No newline at end of file diff --git a/src/xml-plugin/src/test/resources/checks/UseUnoptimizedVectorImage/UseUnoptimizedVectorImage.svg b/src/xml-plugin/src/test/resources/checks/UseUnoptimizedVectorImage/UseUnoptimizedVectorImage.svg new file mode 100644 index 000000000..55af5b8e6 --- /dev/null +++ b/src/xml-plugin/src/test/resources/checks/UseUnoptimizedVectorImage/UseUnoptimizedVectorImage.svg @@ -0,0 +1,56 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="100%" viewBox="0 0 300 300"> + + <title>SVG Logo + Designed for the SVG Logo Contest in 2006 by Harvey Rayner, and adopted by W3C in 2009. It is available under the Creative Commons license for those who have an SVG product or who are using SVG on their site. + + + + + SVG Logo + 14-08-2009 + + W3C + Harvey Rayner, designer + + See document description + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/xml-plugin/src/test/resources/checks/UseUnoptimizedVectorImage/UseUnoptimizedVectorImageSVGO.svg b/src/xml-plugin/src/test/resources/checks/UseUnoptimizedVectorImage/UseUnoptimizedVectorImageSVGO.svg new file mode 100644 index 000000000..e4bffaff2 --- /dev/null +++ b/src/xml-plugin/src/test/resources/checks/UseUnoptimizedVectorImage/UseUnoptimizedVectorImageSVGO.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/xml-plugin/src/test/resources/checks/UseUnoptimizedVectorImage/pom.xml b/src/xml-plugin/src/test/resources/checks/UseUnoptimizedVectorImage/pom.xml new file mode 100644 index 000000000..5179dca0b --- /dev/null +++ b/src/xml-plugin/src/test/resources/checks/UseUnoptimizedVectorImage/pom.xml @@ -0,0 +1,265 @@ + + + 4.0.0 + + + org.springframework.boot + spring-boot-starter-parent + 2.6.2 + + fr.cats + sonarlysa-web + 0.0.4 + sonarlysa-web + IHM de SonarLysa + jar + + + mon titre + 1.8 + jdt_apt + 4.2.1 + 1.18.6 + UTF-8 + + 1.4.2.Final + + target/site/jacoco + target/jacoco.exec + + + + + + org.springframework.boot + spring-boot-starter-actuator + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + org.thymeleaf.extras + thymeleaf-extras-springsecurity5 + + + + + org.springframework.boot + spring-boot-starter-security + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + org.springframework.boot + spring-boot-starter-mail + 2.4.3 + + + + + org.webjars + bootstrap + ${bootstrap.version} + + + + + org.projectlombok + lombok + provided + + + + + org.json + json + 20210307 + + + + + com.google.code.gson + gson + 2.8.9 + + + + + org.apache.poi + poi-ooxml + 5.1.0 + + + + + org.bouncycastle + bcprov-jdk14 + 1.69 + + + + + + com.lowagie + itext + 2.1.7 + + + org.bouncycastle + bcprov-jdk14 + + + + + + + net.sourceforge.dynamicreports + dynamicreports-core + 6.12.1 + + + com.lowagie + itext + + + + + + + org.mapstruct + mapstruct + ${map.structure.version} + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.8 + 1.8 + 3 + true + -Xmx1024m -XX:MaxPermSize=256m + + + org.mapstruct + mapstruct-processor + ${map.structure.version} + + + org.projectlombok + lombok + ${lombok.version} + + + + + + + org.jacoco + jacoco-maven-plugin + 0.8.7 + + + pre-unit-tests + + prepare-agent + + + + ${sonar.jacoco.reportPath} + + + + + post-unit-test + test + + report + + + ${sonar.jacoco.reportPath} + + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + true + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.0.0-M5 + + + + + + + + + + + From 2256ea7b9a2e744d5517d5eea437c7611144e91d Mon Sep 17 00:00:00 2001 From: "Antoine.Meheut" <34522927+AntoineMeheut@users.noreply.github.com> Date: Fri, 17 Jun 2022 12:08:56 +0200 Subject: [PATCH 036/119] 64-PYTHON (#135) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Create COPYING Proposal to add the COPYING file of the GNU General Public License v3.0 * Start 64-PYTHON add AvoidSQLRequestInLoop rule * ahmed partie HTML/JSON * 4 fichiers ajouté html/json/python/java-test * ajout partie executemany * modification code de test.py * Start 64-PYTHON add AvoidSQLRequestInLoop rule * Remise en place * test * final * final * rename S64 files * Update AvoidSQLRequestInLoop.java * Update AvoidSQLRequestInLoopCheck.py * Delete COPYING * clean code * Update AvoidSQLRequestInLoop.java * Update AvoidSQLRequestInLoop.java Co-authored-by: Ahmed Bahri Co-authored-by: ahmedcove1 Co-authored-by: omargaizi --- .idea/.gitignore | 8 ++ .idea/ecoCode.iml | 9 ++ .idea/inspectionProfiles/Project_Default.xml | 6 ++ .idea/misc.xml | 4 + .idea/modules.xml | 8 ++ .idea/vcs.xml | 6 ++ .../fr/cnumr/l10n/python/rules/python/64.html | 48 +++++++++++ .../fr/cnumr/l10n/python/rules/python/64.json | 14 ++++ .../AvoidSQLRequestInLoopCheckTest.java | 12 +++ .../checks/AvoidSQLRequestInLoopCheck.py | 64 ++++++++++++++ src/python-plugin/pom.xml | 6 ++ .../python/checks/AvoidSQLRequestInLoop.java | 83 +++++++++++++++++++ .../cnumr/l10n/python/rules/python/S64.html | 49 +++++++++++ .../cnumr/l10n/python/rules/python/S64.json | 14 ++++ .../AvoidSQLRequestInLoopCheckTest.java | 12 +++ .../checks/AvoidSQLRequestInLoopCheck.py | 64 ++++++++++++++ 16 files changed, 407 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 .idea/ecoCode.iml create mode 100644 .idea/inspectionProfiles/Project_Default.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 sonarqube-plugin-greenit/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/64.html create mode 100644 sonarqube-plugin-greenit/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/64.json create mode 100644 sonarqube-plugin-greenit/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidSQLRequestInLoopCheckTest.java create mode 100644 sonarqube-plugin-greenit/python-plugin/src/test/resources/checks/AvoidSQLRequestInLoopCheck.py create mode 100644 src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidSQLRequestInLoop.java create mode 100644 src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S64.html create mode 100644 src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S64.json create mode 100644 src/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidSQLRequestInLoopCheckTest.java create mode 100644 src/python-plugin/src/test/resources/checks/AvoidSQLRequestInLoopCheck.py diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 000000000..13566b81b --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/ecoCode.iml b/.idea/ecoCode.iml new file mode 100644 index 000000000..d6ebd4805 --- /dev/null +++ b/.idea/ecoCode.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 000000000..ac21435ff --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 000000000..412cda9dd --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 000000000..648097b9c --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 000000000..35eb1ddfb --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/sonarqube-plugin-greenit/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/64.html b/sonarqube-plugin-greenit/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/64.html new file mode 100644 index 000000000..d40de7588 --- /dev/null +++ b/sonarqube-plugin-greenit/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/64.html @@ -0,0 +1,48 @@ +

Do not execute an SQL request in a loop

+

Noncompliant Code Example

+
+
+    def foo():
+        ...
+        baseQuery= "SELECT name FROM users where id = "
+        for i in range(0,20):
+            query=query + str(i)
+            cursor.execute(query) #Noncompliant
+            for row in cursor:
+                print(row)
+        ...
+        cursor.close()
+-----------------------------------------------------------
+    def foo():
+        ...
+        baseQuery= "SELECT name FROM users where id = "
+        data = [ i for i in range(0,20) ]
+        cursor.executemany(baseQuery,data)
+        for row in cursor:
+            print(row)
+        ...
+        cursor.close()
+
+
+ + +

Compliant Solution

+
+
+    def  foo() {
+        ...
+        query = "SELECT name FROM users where id in (0 "
+        for i in range(0,20):
+            query = query +","+str(i)
+        query+=")"
+        cursor.execute(query) #compliant
+
+        # iterate through the  resultset
+        for row in cursor:
+            print(row)
+
+        cursor.close();
+        ...
+   }
+
+
diff --git a/sonarqube-plugin-greenit/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/64.json b/sonarqube-plugin-greenit/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/64.json new file mode 100644 index 000000000..7f1dc865f --- /dev/null +++ b/sonarqube-plugin-greenit/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/64.json @@ -0,0 +1,14 @@ +{ + "title": "Avoid SQL request in loop", + "type": "CODE_SMELL", + + "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "10min" + }, + "tags": [ + "eco-conception" + ], + "defaultSeverity": "Minor" +} \ No newline at end of file diff --git a/sonarqube-plugin-greenit/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidSQLRequestInLoopCheckTest.java b/sonarqube-plugin-greenit/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidSQLRequestInLoopCheckTest.java new file mode 100644 index 000000000..dc5a47206 --- /dev/null +++ b/sonarqube-plugin-greenit/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidSQLRequestInLoopCheckTest.java @@ -0,0 +1,12 @@ +package fr.cnumr.python.checks; + +import org.junit.Test; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class AvoidSQLRequestInLoopCheckTest { + + @Test + public void test() { + PythonCheckVerifier.verify("src/test/resources/checks/AvoidSQLRequestInLoopCheck.py", new AvoidSQLRequestInLoopCheckTest()); + } +} \ No newline at end of file diff --git a/sonarqube-plugin-greenit/python-plugin/src/test/resources/checks/AvoidSQLRequestInLoopCheck.py b/sonarqube-plugin-greenit/python-plugin/src/test/resources/checks/AvoidSQLRequestInLoopCheck.py new file mode 100644 index 000000000..1b0412875 --- /dev/null +++ b/sonarqube-plugin-greenit/python-plugin/src/test/resources/checks/AvoidSQLRequestInLoopCheck.py @@ -0,0 +1,64 @@ +import mysql.connector + + +class AvoidSQLRequestInLoopCheck: + def testWithNoLoop(self): + try : + db = mysql.connector.connect(option_files='my.conf', use_pure=True) + cursor=db.cursor() + query = "SELECT * FROM users" + cursor.execute(query) + with row in cursor: + print(row.id) + cursor.close() + db.close() + except : + print("Got an exception") + db.close() + + def testWithForLoop(): + try: + db = mysql.connector.connect(option_files='my.conf', use_pure=True) + query = "SELECT * FROM users where id = " + for i in range(0,20): + cursor=db.cursor() + query+=str(i) + cursor.execute(query) #Noncompliant + with row in cursor: + print(row.name) + cursor.close() + except : + print("Got an exception") + db.close() + + def testWithWhileLoop(): + try: + db = mysql.connector.connect(option_files='my.conf', use_pure=True) + query = "SELECT * FROM users where id = " + i = 0 + while i<20: + + cursor=db.cursor() + query+=str(i) + cursor.execute(query) #Noncompliant + with row in cursor: + print(row.name) + cursor.close() + i+=1 + except : + print("Got an exception") + db.close() + + def testWithExecuteMany(): + try: + db =db = mysql.connector.connect(option_files='my.conf', use_pure=True) + query = "SELECT * FROM users where id = %d" + cursor=db.cursor() + data = [i for i in range(20)] + cursor.executemany(query,data) + with row in cursor: + print(row.name) + cursor.close() + except: + print("Got an exception") + db.close() \ No newline at end of file diff --git a/src/python-plugin/pom.xml b/src/python-plugin/pom.xml index 7ed2f4244..2e9477fba 100644 --- a/src/python-plugin/pom.xml +++ b/src/python-plugin/pom.xml @@ -40,6 +40,12 @@ org.sonarsource.sonarqube sonar-plugin-api-impl + + org.sonarsource.java + java-frontend + 6.3.0.21585 + compile + diff --git a/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidSQLRequestInLoop.java b/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidSQLRequestInLoop.java new file mode 100644 index 000000000..6c4a426a7 --- /dev/null +++ b/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidSQLRequestInLoop.java @@ -0,0 +1,83 @@ +package fr.cnumr.python.checks; + +import org.sonar.check.Priority; +import org.sonar.check.Rule; +import org.sonar.plugins.python.api.PythonSubscriptionCheck; +import org.sonar.plugins.python.api.tree.*; + +import java.util.*; + + +@Rule( + key = "S64", + name = "Developpement", + description = AvoidSQLRequestInLoop.MESSAGERULE, + priority = Priority.MINOR, + tags = {"bug"}) +public class AvoidSQLRequestInLoop extends PythonSubscriptionCheck { + + public static final String MESSAGERULE = "Avoid perform an SQL query inside a loop"; + private static final Map> linesWithIssuesByFile = new HashMap<>(); + + @Override + public void initialize(Context context) { + + context.registerSyntaxNodeConsumer(Tree.Kind.FOR_STMT, ctx -> { + ForStatement forStatement = (ForStatement) ctx.syntaxNode(); + StatementList list = (StatementList) forStatement.body(); + for (Statement a : list.statements()) { + if (a.getKind().equals(Tree.Kind.EXPRESSION_STMT)) { + ExpressionStatement expression = (ExpressionStatement) a; + for (Expression i : expression.expressions()) { + CallExpression call = (CallExpression) i; + for (Tree ele : call.callee().children()) { + + if (ele.getKind().equals(Tree.Kind.NAME)) { + Name name = (Name) ele; + if (name.name().equals("execute")) { + for (Argument argument : call.arguments()) { + StringLiteral string = (StringLiteral) argument.children().get(0); + if (string.stringElements().get(0).value().toUpperCase().contains("SELECT")) { + ctx.addIssue(call, MESSAGERULE); + } + } + } + } + } + } + } + } + + + }); + context.registerSyntaxNodeConsumer(Tree.Kind.WHILE_STMT, ctx -> { + WhileStatement forStatement = (WhileStatement) ctx.syntaxNode(); + StatementList list = (StatementList) forStatement.body(); + for (Statement a : list.statements()) { + if (a.getKind().equals(Tree.Kind.EXPRESSION_STMT)) { + ExpressionStatement expression = (ExpressionStatement) a; + for (Expression i : expression.expressions()) { + CallExpression call = (CallExpression) i; + for (Tree ele : call.callee().children()) { + if (ele.getKind().equals(Tree.Kind.NAME)) { + Name name = (Name) ele; + if (name.name().equals("execute")) { + for (Argument argument : call.arguments()) { + StringLiteral string = (StringLiteral) argument.children().get(0); + if (string.stringElements().get(0).value().toUpperCase().contains("SELECT")) { + ctx.addIssue(call, MESSAGERULE); + + } + } + } + } + } + } + + } + } + + }); + } + +} diff --git a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S64.html b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S64.html new file mode 100644 index 000000000..61e1620cb --- /dev/null +++ b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S64.html @@ -0,0 +1,49 @@ +

Do not execute an SQL request in a loop

+

Noncompliant Code Example

+
+
+    def foo():
+        ...
+        baseQuery = "SELECT name FROM users where id = "
+        for i in range(0,20):
+            query = query + str(i)
+            cursor.execute(query) # Noncompliant
+            for row in cursor:
+                print(row)
+        ...
+        cursor.close()
+-----------------------------------------------------------
+    def foo():
+        ...
+        baseQuery = "SELECT name FROM users where id = "
+        data = [ i for i in range(0,20) ]
+        cursor.executemany(baseQuery,data)
+        for row in cursor:
+            print(row)
+        ...
+        cursor.close()
+
+
+ + +

Compliant Solution

+
+
+    def  foo() {
+        ...
+        query = "SELECT name FROM users where id in (0 "
+        for i in range(0,20):
+            query = query + "," + str(i)
+        query += ")"
+        cursor.execute(query) # Compliant
+
+        # iterate through the resultset
+        for row in cursor:
+            print(row)
+
+        cursor.close();
+        ...
+   }
+
+
+ diff --git a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S64.json b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S64.json new file mode 100644 index 000000000..b86e91d8a --- /dev/null +++ b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S64.json @@ -0,0 +1,14 @@ +{ + "title": "Avoid SQL request in loop", + "type": "CODE_SMELL", + + "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "10min" + }, + "tags": [ + "eco-conception" + ], + "defaultSeverity": "Minor" +} diff --git a/src/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidSQLRequestInLoopCheckTest.java b/src/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidSQLRequestInLoopCheckTest.java new file mode 100644 index 000000000..57aa12412 --- /dev/null +++ b/src/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidSQLRequestInLoopCheckTest.java @@ -0,0 +1,12 @@ +package fr.cnumr.python.checks; + +import org.junit.Test; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class AvoidSQLRequestInLoopCheckTest { + + @Test + public void test() { + PythonCheckVerifier.verify("src/test/resources/checks/AvoidSQLRequestInLoopCheck.py", new AvoidSQLRequestInLoop()); + } +} diff --git a/src/python-plugin/src/test/resources/checks/AvoidSQLRequestInLoopCheck.py b/src/python-plugin/src/test/resources/checks/AvoidSQLRequestInLoopCheck.py new file mode 100644 index 000000000..177d70a1d --- /dev/null +++ b/src/python-plugin/src/test/resources/checks/AvoidSQLRequestInLoopCheck.py @@ -0,0 +1,64 @@ +import mysql.connector + + +class AvoidSQLRequestInLoopCheck: + def testWithNoLoop(self): + try : + db = mysql.connector.connect(option_files='my.conf', use_pure=True) + cursor=db.cursor() + query = "SELECT * FROM users" + cursor.execute(query) + with row in cursor: + print(row.id) + cursor.close() + db.close() + except : + print("Got an exception") + db.close() + + def testWithForLoop(): + try: + db = mysql.connector.connect(option_files='my.conf', use_pure=True) + cursor=db.cursor() + for i in range(0,20): + query+=str(i) + cursor.execute("SELECT * from users") #Noncompliant + + with row in cursor: + print(row.name) + cursor.close() + except : + print("Got an exception") + db.close() + + def testWithWhileLoop(): + try: + db = mysql.connector.connect(option_files='my.conf', use_pure=True) + query = "SELECT * " + i = 0 + while i<20: + cursor=db.cursor() + cursor.execute("SELECT * FROM users where id = "+str(i)) #Noncompliant + i+=1 + with row in cursor: + print(row.name) + cursor.close() + except : + print("Got an exception") + db.close() + def testWithWhileLoop(): + try: + db = mysql.connector.connect(option_files='my.conf', use_pure=True) + i = 0 + while i<20: + cursor=db.cursor() + cursor.execute("UPDATE users set id="+str(i)) + i+=1 + with row in cursor: + print(row.name) + cursor.close() + except : + print("Got an exception") + db.close() + + From ba491934c77fd2ad4bcd0a798f9bb2126b805e4a Mon Sep 17 00:00:00 2001 From: Jules Delecour <72793427+jules-delecour-dav@users.noreply.github.com> Date: Fri, 17 Jun 2022 12:51:07 +0200 Subject: [PATCH 037/119] Revert "64-PYTHON (#135)" (#138) This reverts commit 2256ea7b9a2e744d5517d5eea437c7611144e91d. --- .idea/.gitignore | 8 -- .idea/ecoCode.iml | 9 -- .idea/inspectionProfiles/Project_Default.xml | 6 -- .idea/misc.xml | 4 - .idea/modules.xml | 8 -- .idea/vcs.xml | 6 -- .../fr/cnumr/l10n/python/rules/python/64.html | 48 ----------- .../fr/cnumr/l10n/python/rules/python/64.json | 14 ---- .../AvoidSQLRequestInLoopCheckTest.java | 12 --- .../checks/AvoidSQLRequestInLoopCheck.py | 64 -------------- src/python-plugin/pom.xml | 6 -- .../python/checks/AvoidSQLRequestInLoop.java | 83 ------------------- .../cnumr/l10n/python/rules/python/S64.html | 49 ----------- .../cnumr/l10n/python/rules/python/S64.json | 14 ---- .../AvoidSQLRequestInLoopCheckTest.java | 12 --- .../checks/AvoidSQLRequestInLoopCheck.py | 64 -------------- 16 files changed, 407 deletions(-) delete mode 100644 .idea/.gitignore delete mode 100644 .idea/ecoCode.iml delete mode 100644 .idea/inspectionProfiles/Project_Default.xml delete mode 100644 .idea/misc.xml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/vcs.xml delete mode 100644 sonarqube-plugin-greenit/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/64.html delete mode 100644 sonarqube-plugin-greenit/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/64.json delete mode 100644 sonarqube-plugin-greenit/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidSQLRequestInLoopCheckTest.java delete mode 100644 sonarqube-plugin-greenit/python-plugin/src/test/resources/checks/AvoidSQLRequestInLoopCheck.py delete mode 100644 src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidSQLRequestInLoop.java delete mode 100644 src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S64.html delete mode 100644 src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S64.json delete mode 100644 src/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidSQLRequestInLoopCheckTest.java delete mode 100644 src/python-plugin/src/test/resources/checks/AvoidSQLRequestInLoopCheck.py diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 13566b81b..000000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Editor-based HTTP Client requests -/httpRequests/ -# Datasource local storage ignored files -/dataSources/ -/dataSources.local.xml diff --git a/.idea/ecoCode.iml b/.idea/ecoCode.iml deleted file mode 100644 index d6ebd4805..000000000 --- a/.idea/ecoCode.iml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml deleted file mode 100644 index ac21435ff..000000000 --- a/.idea/inspectionProfiles/Project_Default.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 412cda9dd..000000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 648097b9c..000000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 35eb1ddfb..000000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/sonarqube-plugin-greenit/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/64.html b/sonarqube-plugin-greenit/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/64.html deleted file mode 100644 index d40de7588..000000000 --- a/sonarqube-plugin-greenit/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/64.html +++ /dev/null @@ -1,48 +0,0 @@ -

Do not execute an SQL request in a loop

-

Noncompliant Code Example

-
-
-    def foo():
-        ...
-        baseQuery= "SELECT name FROM users where id = "
-        for i in range(0,20):
-            query=query + str(i)
-            cursor.execute(query) #Noncompliant
-            for row in cursor:
-                print(row)
-        ...
-        cursor.close()
------------------------------------------------------------
-    def foo():
-        ...
-        baseQuery= "SELECT name FROM users where id = "
-        data = [ i for i in range(0,20) ]
-        cursor.executemany(baseQuery,data)
-        for row in cursor:
-            print(row)
-        ...
-        cursor.close()
-
-
- - -

Compliant Solution

-
-
-    def  foo() {
-        ...
-        query = "SELECT name FROM users where id in (0 "
-        for i in range(0,20):
-            query = query +","+str(i)
-        query+=")"
-        cursor.execute(query) #compliant
-
-        # iterate through the  resultset
-        for row in cursor:
-            print(row)
-
-        cursor.close();
-        ...
-   }
-
-
diff --git a/sonarqube-plugin-greenit/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/64.json b/sonarqube-plugin-greenit/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/64.json deleted file mode 100644 index 7f1dc865f..000000000 --- a/sonarqube-plugin-greenit/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/64.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "title": "Avoid SQL request in loop", - "type": "CODE_SMELL", - - "status": "ready", - "remediation": { - "func": "Constant\/Issue", - "constantCost": "10min" - }, - "tags": [ - "eco-conception" - ], - "defaultSeverity": "Minor" -} \ No newline at end of file diff --git a/sonarqube-plugin-greenit/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidSQLRequestInLoopCheckTest.java b/sonarqube-plugin-greenit/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidSQLRequestInLoopCheckTest.java deleted file mode 100644 index dc5a47206..000000000 --- a/sonarqube-plugin-greenit/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidSQLRequestInLoopCheckTest.java +++ /dev/null @@ -1,12 +0,0 @@ -package fr.cnumr.python.checks; - -import org.junit.Test; -import org.sonar.python.checks.utils.PythonCheckVerifier; - -public class AvoidSQLRequestInLoopCheckTest { - - @Test - public void test() { - PythonCheckVerifier.verify("src/test/resources/checks/AvoidSQLRequestInLoopCheck.py", new AvoidSQLRequestInLoopCheckTest()); - } -} \ No newline at end of file diff --git a/sonarqube-plugin-greenit/python-plugin/src/test/resources/checks/AvoidSQLRequestInLoopCheck.py b/sonarqube-plugin-greenit/python-plugin/src/test/resources/checks/AvoidSQLRequestInLoopCheck.py deleted file mode 100644 index 1b0412875..000000000 --- a/sonarqube-plugin-greenit/python-plugin/src/test/resources/checks/AvoidSQLRequestInLoopCheck.py +++ /dev/null @@ -1,64 +0,0 @@ -import mysql.connector - - -class AvoidSQLRequestInLoopCheck: - def testWithNoLoop(self): - try : - db = mysql.connector.connect(option_files='my.conf', use_pure=True) - cursor=db.cursor() - query = "SELECT * FROM users" - cursor.execute(query) - with row in cursor: - print(row.id) - cursor.close() - db.close() - except : - print("Got an exception") - db.close() - - def testWithForLoop(): - try: - db = mysql.connector.connect(option_files='my.conf', use_pure=True) - query = "SELECT * FROM users where id = " - for i in range(0,20): - cursor=db.cursor() - query+=str(i) - cursor.execute(query) #Noncompliant - with row in cursor: - print(row.name) - cursor.close() - except : - print("Got an exception") - db.close() - - def testWithWhileLoop(): - try: - db = mysql.connector.connect(option_files='my.conf', use_pure=True) - query = "SELECT * FROM users where id = " - i = 0 - while i<20: - - cursor=db.cursor() - query+=str(i) - cursor.execute(query) #Noncompliant - with row in cursor: - print(row.name) - cursor.close() - i+=1 - except : - print("Got an exception") - db.close() - - def testWithExecuteMany(): - try: - db =db = mysql.connector.connect(option_files='my.conf', use_pure=True) - query = "SELECT * FROM users where id = %d" - cursor=db.cursor() - data = [i for i in range(20)] - cursor.executemany(query,data) - with row in cursor: - print(row.name) - cursor.close() - except: - print("Got an exception") - db.close() \ No newline at end of file diff --git a/src/python-plugin/pom.xml b/src/python-plugin/pom.xml index 2e9477fba..7ed2f4244 100644 --- a/src/python-plugin/pom.xml +++ b/src/python-plugin/pom.xml @@ -40,12 +40,6 @@ org.sonarsource.sonarqube sonar-plugin-api-impl - - org.sonarsource.java - java-frontend - 6.3.0.21585 - compile - diff --git a/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidSQLRequestInLoop.java b/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidSQLRequestInLoop.java deleted file mode 100644 index 6c4a426a7..000000000 --- a/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidSQLRequestInLoop.java +++ /dev/null @@ -1,83 +0,0 @@ -package fr.cnumr.python.checks; - -import org.sonar.check.Priority; -import org.sonar.check.Rule; -import org.sonar.plugins.python.api.PythonSubscriptionCheck; -import org.sonar.plugins.python.api.tree.*; - -import java.util.*; - - -@Rule( - key = "S64", - name = "Developpement", - description = AvoidSQLRequestInLoop.MESSAGERULE, - priority = Priority.MINOR, - tags = {"bug"}) -public class AvoidSQLRequestInLoop extends PythonSubscriptionCheck { - - public static final String MESSAGERULE = "Avoid perform an SQL query inside a loop"; - private static final Map> linesWithIssuesByFile = new HashMap<>(); - - @Override - public void initialize(Context context) { - - context.registerSyntaxNodeConsumer(Tree.Kind.FOR_STMT, ctx -> { - ForStatement forStatement = (ForStatement) ctx.syntaxNode(); - StatementList list = (StatementList) forStatement.body(); - for (Statement a : list.statements()) { - if (a.getKind().equals(Tree.Kind.EXPRESSION_STMT)) { - ExpressionStatement expression = (ExpressionStatement) a; - for (Expression i : expression.expressions()) { - CallExpression call = (CallExpression) i; - for (Tree ele : call.callee().children()) { - - if (ele.getKind().equals(Tree.Kind.NAME)) { - Name name = (Name) ele; - if (name.name().equals("execute")) { - for (Argument argument : call.arguments()) { - StringLiteral string = (StringLiteral) argument.children().get(0); - if (string.stringElements().get(0).value().toUpperCase().contains("SELECT")) { - ctx.addIssue(call, MESSAGERULE); - } - } - } - } - } - } - } - } - - - }); - context.registerSyntaxNodeConsumer(Tree.Kind.WHILE_STMT, ctx -> { - WhileStatement forStatement = (WhileStatement) ctx.syntaxNode(); - StatementList list = (StatementList) forStatement.body(); - for (Statement a : list.statements()) { - if (a.getKind().equals(Tree.Kind.EXPRESSION_STMT)) { - ExpressionStatement expression = (ExpressionStatement) a; - for (Expression i : expression.expressions()) { - CallExpression call = (CallExpression) i; - for (Tree ele : call.callee().children()) { - if (ele.getKind().equals(Tree.Kind.NAME)) { - Name name = (Name) ele; - if (name.name().equals("execute")) { - for (Argument argument : call.arguments()) { - StringLiteral string = (StringLiteral) argument.children().get(0); - if (string.stringElements().get(0).value().toUpperCase().contains("SELECT")) { - ctx.addIssue(call, MESSAGERULE); - - } - } - } - } - } - } - - } - } - - }); - } - -} diff --git a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S64.html b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S64.html deleted file mode 100644 index 61e1620cb..000000000 --- a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S64.html +++ /dev/null @@ -1,49 +0,0 @@ -

Do not execute an SQL request in a loop

-

Noncompliant Code Example

-
-
-    def foo():
-        ...
-        baseQuery = "SELECT name FROM users where id = "
-        for i in range(0,20):
-            query = query + str(i)
-            cursor.execute(query) # Noncompliant
-            for row in cursor:
-                print(row)
-        ...
-        cursor.close()
------------------------------------------------------------
-    def foo():
-        ...
-        baseQuery = "SELECT name FROM users where id = "
-        data = [ i for i in range(0,20) ]
-        cursor.executemany(baseQuery,data)
-        for row in cursor:
-            print(row)
-        ...
-        cursor.close()
-
-
- - -

Compliant Solution

-
-
-    def  foo() {
-        ...
-        query = "SELECT name FROM users where id in (0 "
-        for i in range(0,20):
-            query = query + "," + str(i)
-        query += ")"
-        cursor.execute(query) # Compliant
-
-        # iterate through the resultset
-        for row in cursor:
-            print(row)
-
-        cursor.close();
-        ...
-   }
-
-
- diff --git a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S64.json b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S64.json deleted file mode 100644 index b86e91d8a..000000000 --- a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S64.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "title": "Avoid SQL request in loop", - "type": "CODE_SMELL", - - "status": "ready", - "remediation": { - "func": "Constant\/Issue", - "constantCost": "10min" - }, - "tags": [ - "eco-conception" - ], - "defaultSeverity": "Minor" -} diff --git a/src/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidSQLRequestInLoopCheckTest.java b/src/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidSQLRequestInLoopCheckTest.java deleted file mode 100644 index 57aa12412..000000000 --- a/src/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidSQLRequestInLoopCheckTest.java +++ /dev/null @@ -1,12 +0,0 @@ -package fr.cnumr.python.checks; - -import org.junit.Test; -import org.sonar.python.checks.utils.PythonCheckVerifier; - -public class AvoidSQLRequestInLoopCheckTest { - - @Test - public void test() { - PythonCheckVerifier.verify("src/test/resources/checks/AvoidSQLRequestInLoopCheck.py", new AvoidSQLRequestInLoop()); - } -} diff --git a/src/python-plugin/src/test/resources/checks/AvoidSQLRequestInLoopCheck.py b/src/python-plugin/src/test/resources/checks/AvoidSQLRequestInLoopCheck.py deleted file mode 100644 index 177d70a1d..000000000 --- a/src/python-plugin/src/test/resources/checks/AvoidSQLRequestInLoopCheck.py +++ /dev/null @@ -1,64 +0,0 @@ -import mysql.connector - - -class AvoidSQLRequestInLoopCheck: - def testWithNoLoop(self): - try : - db = mysql.connector.connect(option_files='my.conf', use_pure=True) - cursor=db.cursor() - query = "SELECT * FROM users" - cursor.execute(query) - with row in cursor: - print(row.id) - cursor.close() - db.close() - except : - print("Got an exception") - db.close() - - def testWithForLoop(): - try: - db = mysql.connector.connect(option_files='my.conf', use_pure=True) - cursor=db.cursor() - for i in range(0,20): - query+=str(i) - cursor.execute("SELECT * from users") #Noncompliant - - with row in cursor: - print(row.name) - cursor.close() - except : - print("Got an exception") - db.close() - - def testWithWhileLoop(): - try: - db = mysql.connector.connect(option_files='my.conf', use_pure=True) - query = "SELECT * " - i = 0 - while i<20: - cursor=db.cursor() - cursor.execute("SELECT * FROM users where id = "+str(i)) #Noncompliant - i+=1 - with row in cursor: - print(row.name) - cursor.close() - except : - print("Got an exception") - db.close() - def testWithWhileLoop(): - try: - db = mysql.connector.connect(option_files='my.conf', use_pure=True) - i = 0 - while i<20: - cursor=db.cursor() - cursor.execute("UPDATE users set id="+str(i)) - i+=1 - with row in cursor: - print(row.name) - cursor.close() - except : - print("Got an exception") - db.close() - - From 007aab683ee4ba0d47853038f169254c30578c27 Mon Sep 17 00:00:00 2001 From: Azelytof <50252147+Azel-ytof@users.noreply.github.com> Date: Fri, 17 Jun 2022 15:44:47 +0200 Subject: [PATCH 038/119] Feature/d4 python (#133) * D4 - Python : Avoid global variable in function * D4 - Python : Avoid global variable in function * Refacto and correction * Uncomment tests in resources * Correction test --- .../python/CustomPythonRuleRepository.java | 9 +- .../AvoidGlobalVariableInFunctionCheck.java | 283 ++++++++++++++++++ .../fr/cnumr/l10n/python/rules/python/D4.html | 20 ++ .../fr/cnumr/l10n/python/rules/python/D4.json | 13 + .../CustomPythonRuleRepositoryTest.java | 4 +- ...voidGlobalVariableInFunctionCheckTest.java | 11 + .../checks/avoidGlobalVariableInFunction.py | 43 +++ 7 files changed, 375 insertions(+), 8 deletions(-) create mode 100644 src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidGlobalVariableInFunctionCheck.java create mode 100644 src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/D4.html create mode 100644 src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/D4.json create mode 100644 src/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidGlobalVariableInFunctionCheckTest.java create mode 100644 src/python-plugin/src/test/resources/checks/avoidGlobalVariableInFunction.py diff --git a/src/python-plugin/src/main/java/fr/cnumr/python/CustomPythonRuleRepository.java b/src/python-plugin/src/main/java/fr/cnumr/python/CustomPythonRuleRepository.java index e1876a4e0..2333305c3 100644 --- a/src/python-plugin/src/main/java/fr/cnumr/python/CustomPythonRuleRepository.java +++ b/src/python-plugin/src/main/java/fr/cnumr/python/CustomPythonRuleRepository.java @@ -20,10 +20,7 @@ package fr.cnumr.python; -import fr.cnumr.python.checks.AvoidDoubleQuoteCheck; -import fr.cnumr.python.checks.AvoidFullSQLRequest; -import fr.cnumr.python.checks.AvoidTryCatchFinallyCheck; -import fr.cnumr.python.checks.NoFunctionCallWhenDeclaringForLoop; +import fr.cnumr.python.checks.*; import org.sonar.api.server.rule.RulesDefinition; import org.sonar.plugins.python.api.PythonCustomRuleRepository; import org.sonarsource.analyzer.commons.RuleMetadataLoader; @@ -57,8 +54,8 @@ public String repositoryKey() { @Override public List checkClasses() { - return Arrays.asList(NoFunctionCallWhenDeclaringForLoop.class, AvoidTryCatchFinallyCheck.class, - AvoidDoubleQuoteCheck.class,AvoidFullSQLRequest.class); + return Arrays.asList(NoFunctionCallWhenDeclaringForLoop.class, AvoidTryCatchFinallyCheck.class, + AvoidDoubleQuoteCheck.class, AvoidFullSQLRequest.class, AvoidGlobalVariableInFunctionCheck.class); } private static void setTemplates(NewRepository repository) { diff --git a/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidGlobalVariableInFunctionCheck.java b/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidGlobalVariableInFunctionCheck.java new file mode 100644 index 000000000..9583127c9 --- /dev/null +++ b/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidGlobalVariableInFunctionCheck.java @@ -0,0 +1,283 @@ +package fr.cnumr.python.checks; + +import org.sonar.api.utils.log.Logger; +import org.sonar.api.utils.log.Loggers; +import org.sonar.check.Priority; +import org.sonar.check.Rule; +import org.sonar.plugins.python.api.PythonSubscriptionCheck; +import org.sonar.plugins.python.api.SubscriptionCheck; +import org.sonar.plugins.python.api.SubscriptionContext; +import org.sonar.plugins.python.api.symbols.Symbol; +import org.sonar.plugins.python.api.tree.*; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Rule( + key = AvoidGlobalVariableInFunctionCheck.RULE_KEY, + name = "Developpement", + description = AvoidGlobalVariableInFunctionCheck.DESCRIPTION, + priority = Priority.MINOR, + tags = {"bug"}) +public class AvoidGlobalVariableInFunctionCheck extends PythonSubscriptionCheck { + private static final Logger LOGGER = Loggers.get(AvoidGlobalVariableInFunctionCheck.class); + + public static final String RULE_KEY = "D4"; + public static final String DESCRIPTION = "Use local variable (function/class scope) instead of global variable (application scope)"; + + private List globalVariables; + private List definedLocalVariables; + private Map usedLocalVariables; + + @Override + public void initialize(SubscriptionCheck.Context context) { + globalVariables = new ArrayList<>(); + context.registerSyntaxNodeConsumer(Tree.Kind.FILE_INPUT, this::visitFileInput); + context.registerSyntaxNodeConsumer(Tree.Kind.FUNCDEF, this::visitFuncDef); + } + + public void visitFileInput(SubscriptionContext ctx) { + FileInput fileInput = (FileInput) ctx.syntaxNode(); + fileInput.globalVariables().stream().filter(v -> v.is(Symbol.Kind.OTHER)).forEach(v -> this.globalVariables.add(v.name())); + } + + void visitFuncDef(SubscriptionContext ctx) { + this.definedLocalVariables = new ArrayList<>(); + this.usedLocalVariables = new HashMap<>(); + + FunctionDef functionDef = (FunctionDef) ctx.syntaxNode(); + + ParameterList parameterList = functionDef.parameters(); + if (parameterList != null) { + parameterList.nonTuple().forEach(p -> extractVariablesFromExpression(p, true)); + } + + functionDef.body().statements() + .forEach(s -> extractVariablesFromExpression(s, false)); + + this.usedLocalVariables.entrySet().stream() + .filter(e -> !this.definedLocalVariables.contains(e.getValue()) && this.globalVariables.contains(e.getValue())) + .forEach(e -> ctx.addIssue(e.getKey(), DESCRIPTION)); + } + + void extractVariablesFromExpression(Tree element, boolean isAssigned) { + if (element == null) { + return; + } + + switch (element.getKind()) { + case REGULAR_ARGUMENT: + extractVariablesFromExpression(((RegularArgument) element).expression(), isAssigned); + break; + case ARG_LIST: + ((ArgList) element).arguments().forEach(a -> extractVariablesFromExpression(a, isAssigned)); + break; + case ANNOTATED_ASSIGNMENT: + AnnotatedAssignment annotatedAssignment = (AnnotatedAssignment) element; + extractVariablesFromExpression(annotatedAssignment.variable(), true); + extractVariablesFromExpression(annotatedAssignment.assignedValue(), false); + break; + case ASSERT_STMT: + AssertStatement assertStatement = (AssertStatement) element; + extractVariablesFromExpression(assertStatement.condition(), false); + extractVariablesFromExpression(assertStatement.message(), false); + break; + case ASSIGNMENT_STMT: + AssignmentStatement assignmentStatement = (AssignmentStatement) element; + assignmentStatement.lhsExpressions().forEach(e -> extractVariablesFromExpression(e, true)); + extractVariablesFromExpression(assignmentStatement.assignedValue(), false); + break; + case CALL_EXPR: + extractVariablesFromExpression(((CallExpression) element).argumentList(), isAssigned); + break; +// TODO : Check if usefull or not +// case CLASSDEF: +// (ClassDef) element; +// break; + case CONDITIONAL_EXPR: + ConditionalExpression conditionalExpression = (ConditionalExpression) element; + extractVariablesFromExpression(conditionalExpression.trueExpression(), isAssigned); + extractVariablesFromExpression(conditionalExpression.falseExpression(), false); + extractVariablesFromExpression(conditionalExpression.condition(), isAssigned); + break; + case COMPOUND_ASSIGNMENT: + CompoundAssignmentStatement compoundAssignmentStatement = (CompoundAssignmentStatement) element; + extractVariablesFromExpression(compoundAssignmentStatement.lhsExpression(), true); + extractVariablesFromExpression(compoundAssignmentStatement.rhsExpression(), false); + break; + case DICTIONARY_LITERAL: + ((DictionaryLiteral) element).elements().forEach(e -> extractVariablesFromExpression(e, false)); + break; + case ELSE_CLAUSE: + extractVariablesFromExpression(((ElseClause) element).body(), isAssigned); + break; + case EXCEPT_CLAUSE: + extractVariablesFromExpression(((ExceptClause) element).body(), isAssigned); + break; + case EXEC_STMT: + ExecStatement execStatement = (ExecStatement) element; + extractVariablesFromExpression(execStatement.expression(), isAssigned); + extractVariablesFromExpression(execStatement.globalsExpression(), isAssigned); + extractVariablesFromExpression(execStatement.localsExpression(), isAssigned); + break; + case EXPRESSION_LIST: + ((ExpressionList) element).expressions().forEach(e -> extractVariablesFromExpression(e, isAssigned)); + break; + case EXPRESSION_STMT: + ((ExpressionStatement) element).expressions().forEach(e -> extractVariablesFromExpression(e, isAssigned)); + break; + case FILE_INPUT: + extractVariablesFromExpression(((FileInput) element).statements(), isAssigned); + break; + case FINALLY_CLAUSE: + extractVariablesFromExpression(((FinallyClause) element).body(), isAssigned); + break; + case FOR_STMT: + ForStatement forStatement = ((ForStatement) element); + forStatement.expressions().forEach(e -> extractVariablesFromExpression(e, true)); + forStatement.testExpressions().forEach(e -> extractVariablesFromExpression(e, false)); + extractVariablesFromExpression(forStatement.body(), isAssigned); + extractVariablesFromExpression(forStatement.elseClause(), isAssigned); + break; + case IF_STMT: + IfStatement ifStatement = (IfStatement) element; + extractVariablesFromExpression(ifStatement.condition(), false); + extractVariablesFromExpression(ifStatement.body(), isAssigned); + extractVariablesFromExpression(ifStatement.elseBranch(), isAssigned); + ifStatement.elifBranches().forEach(b -> extractVariablesFromExpression(b, isAssigned)); + break; + case LAMBDA: + extractVariablesFromExpression(((LambdaExpression) element).expression(), isAssigned); + break; + case LIST_LITERAL: + extractVariablesFromExpression(((ListLiteral) element).elements(), false); + break; + case NAME: + if (isAssigned) { + this.definedLocalVariables.add(((Name) element).name()); + } else { + this.usedLocalVariables.put(element, ((Name) element).name()); + } + break; + case PRINT_STMT: + ((PrintStatement) element).expressions().forEach(e -> extractVariablesFromExpression(e, false)); + break; + case RAISE_STMT: + RaiseStatement raiseStatement = (RaiseStatement) element; + extractVariablesFromExpression(raiseStatement.fromExpression(), false); + raiseStatement.expressions().forEach(e -> extractVariablesFromExpression(e, false)); + break; + case REPR: + extractVariablesFromExpression(((ReprExpression) element).expressionList(), isAssigned); + break; + case RETURN_STMT: + ((ReturnStatement) element).expressions().forEach(e -> extractVariablesFromExpression(e, false)); + break; + case SET_LITERAL: + ((SetLiteral) element).elements().forEach(e -> extractVariablesFromExpression(e, false)); + break; + case STATEMENT_LIST: + ((StatementList) element).statements().forEach(s -> extractVariablesFromExpression(s, isAssigned)); + break; + case TRY_STMT: + TryStatement tryStatement = (TryStatement) element; + extractVariablesFromExpression(tryStatement.body(), isAssigned); + tryStatement.exceptClauses().forEach(c -> extractVariablesFromExpression(c, isAssigned)); + extractVariablesFromExpression(tryStatement.elseClause(), isAssigned); + extractVariablesFromExpression(tryStatement.finallyClause(), isAssigned); + break; + case PARAMETER: + Parameter parameter = (Parameter) element; + extractVariablesFromExpression(parameter.name(), true); + extractVariablesFromExpression(parameter.defaultValue(), false); + break; + case TUPLE_PARAMETER: + ((TupleParameter) element).parameters().forEach(p -> extractVariablesFromExpression(p, isAssigned)); + break; + case PARAMETER_LIST: + ((ParameterList) element).all().forEach(a -> extractVariablesFromExpression(a, true)); + break; + case WHILE_STMT: + WhileStatement whileStatement = (WhileStatement) element; + extractVariablesFromExpression(whileStatement.condition(), false); + extractVariablesFromExpression(whileStatement.body(), isAssigned); + extractVariablesFromExpression(whileStatement.elseClause(), isAssigned); + break; + case YIELD_EXPR: + ((YieldExpression) element).expressions().forEach(e -> extractVariablesFromExpression(e, isAssigned)); + break; + case YIELD_STMT: + extractVariablesFromExpression(((YieldStatement) element).yieldExpression(), isAssigned); + break; + case PARENTHESIZED: + extractVariablesFromExpression(((ParenthesizedExpression) element).expression(), isAssigned); + break; + case UNPACKING_EXPR: + extractVariablesFromExpression(((UnpackingExpression) element).expression(), isAssigned); + break; + case AWAIT: + extractVariablesFromExpression(((AwaitExpression) element).expression(), false); + break; + case TUPLE: + ((Tuple) element).elements().forEach(e -> extractVariablesFromExpression(e, isAssigned)); + break; + case DICT_COMPREHENSION: + extractVariablesFromExpression(((DictCompExpression) element).comprehensionFor(), false); + break; + case LIST_COMPREHENSION: + case SET_COMPREHENSION: + case GENERATOR_EXPR: + extractVariablesFromExpression(((ComprehensionExpression) element).resultExpression(), false); + extractVariablesFromExpression(((ComprehensionExpression) element).comprehensionFor(), true); + break; + case COMP_FOR: + extractVariablesFromExpression(((ComprehensionFor) element).loopExpression(), true); + extractVariablesFromExpression(((ComprehensionFor) element).iterable(), false); + break; + case COMP_IF: + extractVariablesFromExpression(((ComprehensionIf) element).condition(), false); + break; + case SUBSCRIPTION: + extractVariablesFromExpression(((SubscriptionExpression) element).object(), false); + extractVariablesFromExpression(((SubscriptionExpression) element).subscripts(), false); + break; + case PLUS: + case MINUS: + case MULTIPLICATION: + case DIVISION: + case FLOOR_DIVISION: + case MODULO: + case MATRIX_MULTIPLICATION: + case SHIFT_EXPR: + case BITWISE_AND: + case BITWISE_OR: + case BITWISE_XOR: + case AND: + case OR: + case COMPARISON: + case POWER: + BinaryExpression binaryExpression = (BinaryExpression) element; + extractVariablesFromExpression(binaryExpression.leftOperand(), false); + extractVariablesFromExpression(binaryExpression.rightOperand(), false); + break; + case UNARY_PLUS: + case UNARY_MINUS: + case BITWISE_COMPLEMENT: + case NOT: + extractVariablesFromExpression(((UnaryExpression) element).expression(), false); + break; + case ASSIGNMENT_EXPRESSION: + AssignmentExpression assignmentExpression = (AssignmentExpression) element; + extractVariablesFromExpression(assignmentExpression.lhsName(), true); + extractVariablesFromExpression(assignmentExpression.expression(), false); + break; + case KEY_VALUE_PAIR: + KeyValuePair keyValuePair = (KeyValuePair) element; + extractVariablesFromExpression(keyValuePair.key(), true); + extractVariablesFromExpression(keyValuePair.value(), false); + break; + } + } +} diff --git a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/D4.html b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/D4.html new file mode 100644 index 000000000..f4d820293 --- /dev/null +++ b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/D4.html @@ -0,0 +1,20 @@ +

Eviter d'utiliser des variables globales directement

+

Noncompliant Code Example

+
+global_var = 'foo'
+def print_global_var_details():
+    print(len(global_var)) # Noncompliant
+    print('Global var : ', global_var) # Noncompliant {{Use local variable
+    print('Global var : ' + global_var) # Noncompliant {{Use local variable
+print_global_var_details()
+
+

Compliant Solution

+
+global_var = 'foo';
+def print_var_details(local_var) {
+  print(len(local_var));
+  print('Var : ', local_var)
+  print('Var : ' + local_var)
+}
+print_length(global_var);
+
diff --git a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/D4.json b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/D4.json new file mode 100644 index 000000000..5d2e79adb --- /dev/null +++ b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/D4.json @@ -0,0 +1,13 @@ +{ + "title": "Ne pas appeler de variable globale directement dans les fonctions", + "type": "CODE_SMELL", + "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "5min" + }, + "tags": [ + "eco-conception" + ], + "defaultSeverity": "Minor" +} \ No newline at end of file diff --git a/src/python-plugin/src/test/java/fr/cnumr/python/CustomPythonRuleRepositoryTest.java b/src/python-plugin/src/test/java/fr/cnumr/python/CustomPythonRuleRepositoryTest.java index 80c6ff227..b9b20dbbc 100644 --- a/src/python-plugin/src/test/java/fr/cnumr/python/CustomPythonRuleRepositoryTest.java +++ b/src/python-plugin/src/test/java/fr/cnumr/python/CustomPythonRuleRepositoryTest.java @@ -33,7 +33,7 @@ public void test_rule_repository() { customPythonRuleRepository.define(context); assertThat(customPythonRuleRepository.repositoryKey()).isEqualTo(CustomPythonRuleRepository.REPOSITORY_KEY); assertThat(context.repositories()).hasSize(1).extracting("key").containsExactly(customPythonRuleRepository.repositoryKey()); - assertThat(context.repositories().get(0).rules()).hasSize(4); - assertThat(customPythonRuleRepository.checkClasses()).hasSize(4); + assertThat(context.repositories().get(0).rules()).hasSize(5); + assertThat(customPythonRuleRepository.checkClasses()).hasSize(5); } } diff --git a/src/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidGlobalVariableInFunctionCheckTest.java b/src/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidGlobalVariableInFunctionCheckTest.java new file mode 100644 index 000000000..3b75bf356 --- /dev/null +++ b/src/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidGlobalVariableInFunctionCheckTest.java @@ -0,0 +1,11 @@ +package fr.cnumr.python.checks; + +import org.junit.Test; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class AvoidGlobalVariableInFunctionCheckTest { + @Test + public void test() { + PythonCheckVerifier.verify("src/test/resources/checks/avoidGlobalVariableInFunction.py", new AvoidGlobalVariableInFunctionCheck()); + } +} diff --git a/src/python-plugin/src/test/resources/checks/avoidGlobalVariableInFunction.py b/src/python-plugin/src/test/resources/checks/avoidGlobalVariableInFunction.py new file mode 100644 index 000000000..9b77dfa72 --- /dev/null +++ b/src/python-plugin/src/test/resources/checks/avoidGlobalVariableInFunction.py @@ -0,0 +1,43 @@ +global_var = 'global' + +def print_global_var_details(): + print(len(global_var)) # Noncompliant + print('Global var : ', global_var) # Noncompliant + print('Global var : ' + global_var) # Noncompliant + for c in global_var: # Noncompliant + print(c) + if len(global_var) > 0: # Noncompliant + print('global_var len positive') + elif 0 < len(global_var): # Noncompliant + print('global_var len negative') + else: + print('global_var len = 0') + + try: + print(global_var) # Noncompliant + except: + print(global_var) # Noncompliant + else: + print(global_var) # Noncompliant + finally: + print(global_var) # Noncompliant + + assert len(global_var) > 0, 'Failed' # Noncompliant + assert len('test') > 0, 'Failed : ' + global_var # Noncompliant + test = '' + test += global_var # Noncompliant + test = {'test': global_var, 'global_var': 1 } # Noncompliant + +# Compliant +def print_var_length(local_var = global_var): + global_var = 'local' # Here it create a local var and do not use the global var + global_var: str = 'local' # Here it create a local var and do not use the global var + global_var += 'local' # Here it create a local var and do not use the global var + global_var = 'local' if True else 'global' # Here it create a local var and do not use the global var + print(len(global_var)) # Compliant for the use, but not for the name of the var + print(len(local_var)) + for global_var in local_var: # Compliant but not for the name + print(global_var) + +print_global_var_details() +print_var_length(global_var) From bf65a8f9e9f296437b34a84050b334b7d53b34be Mon Sep 17 00:00:00 2001 From: Jules Delecour Date: Fri, 17 Jun 2022 17:48:47 +0200 Subject: [PATCH 039/119] cleaning rule python + cleaning doc --- .../NoFunctionCallWhenDeclaringForLoop.java | 2 +- .../fr/cnumr/l10n/java/rules/java/GRC1.html | 13 ++-- .../fr/cnumr/l10n/java/rules/java/S53.html | 4 +- .../fr/cnumr/l10n/java/rules/java/S63.html | 2 +- .../fr/cnumr/l10n/java/rules/java/S67.html | 2 +- .../fr/cnumr/l10n/java/rules/java/S69.html | 2 +- .../fr/cnumr/l10n/java/rules/java/S69.json | 2 +- .../fr/cnumr/l10n/java/rules/java/S72.html | 2 +- .../fr/cnumr/l10n/java/rules/java/S74.html | 2 +- .../main/java/fr/cnumr/php/MyPhpRules.java | 2 +- .../fr/cnumr/l10n/php/rules/custom/S34.html | 5 +- .../fr/cnumr/l10n/php/rules/custom/S66.html | 3 +- .../fr/cnumr/l10n/php/rules/custom/S66.json | 2 +- .../fr/cnumr/l10n/php/rules/custom/S67.html | 2 +- .../fr/cnumr/l10n/php/rules/custom/S67.json | 2 +- .../fr/cnumr/l10n/php/rules/custom/S69.html | 2 +- .../fr/cnumr/l10n/php/rules/custom/S72.html | 2 +- .../fr/cnumr/l10n/php/rules/custom/S74.html | 2 +- .../python/CustomPythonRuleRepository.java | 5 +- .../python/checks/AvoidDoubleQuoteCheck.java | 73 ------------------- .../NoFunctionCallWhenDeclaringForLoop.java | 2 +- .../fr/cnumr/l10n/python/rules/python/D4.html | 6 +- .../fr/cnumr/l10n/python/rules/python/D4.json | 2 +- .../cnumr/l10n/python/rules/python/S34.html | 4 +- .../cnumr/l10n/python/rules/python/S34.json | 2 +- .../cnumr/l10n/python/rules/python/S66.html | 13 ---- .../cnumr/l10n/python/rules/python/S66.json | 13 ---- .../cnumr/l10n/python/rules/python/S69.json | 2 +- .../cnumr/l10n/python/rules/python/S74.html | 2 +- .../CustomPythonRuleRepositoryTest.java | 4 +- .../checks/AvoidDoubleQuoteCheckTest.java | 12 --- .../test/resources/checks/avoidDoubleQuote.py | 30 -------- .../noFunctionCallWhenDeclaringForLoop.py | 2 +- .../main/java/fr/cnumr/xml/MyXmlRules.java | 2 +- 34 files changed, 44 insertions(+), 183 deletions(-) delete mode 100644 src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidDoubleQuoteCheck.java delete mode 100644 src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S66.html delete mode 100644 src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S66.json delete mode 100644 src/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidDoubleQuoteCheckTest.java delete mode 100644 src/python-plugin/src/test/resources/checks/avoidDoubleQuote.py diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/checks/NoFunctionCallWhenDeclaringForLoop.java b/src/java-plugin/src/main/java/fr/cnumr/java/checks/NoFunctionCallWhenDeclaringForLoop.java index 0c91730f9..1154458a5 100644 --- a/src/java-plugin/src/main/java/fr/cnumr/java/checks/NoFunctionCallWhenDeclaringForLoop.java +++ b/src/java-plugin/src/main/java/fr/cnumr/java/checks/NoFunctionCallWhenDeclaringForLoop.java @@ -28,7 +28,7 @@ tags = {"bug"}) public class NoFunctionCallWhenDeclaringForLoop extends IssuableSubscriptionVisitor { - protected static final String MESSAGERULE = "Do not call a function in the declaration of a for-type loop"; + protected static final String MESSAGERULE = "Do not call a function when declaring a for-type loop"; private static final Map> linesWithIssuesByClass = new HashMap<>(); diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRC1.html b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRC1.html index 9b81f5b10..4b7c6e79a 100644 --- a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRC1.html +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRC1.html @@ -1,12 +1,12 @@ -

Avoid Spring repository call in loop

+

Using Spring repository in loop induced unnecessary calculation by the cpu so unless energy consumption

Noncompliant Code Example

-		private final List ids = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
+		private final List<Integer> ids = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
 
-		List employees = new ArrayList<>();
+		List<Employee> employees = new ArrayList<>();
 		
 		for (Integer id: ids) {
-            Optional employee = employeeRepository.findById(id); // Noncompliant {{Avoid Spring repository call in loop}}
+            Optional<Employee> employee = employeeRepository.findById(id); // Noncompliant
             if (employee.isPresent()) {
                 employees.add(employee.get());
             }
@@ -15,7 +15,6 @@ 

Noncompliant Code Example

Compliant Solution

-		private final List ids = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
-		
-		List employees = employeeRepository.findAllById(ids);
+		private final List<Integer> ids = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
+		List<Employee> employees = employeeRepository.findAllById(ids);
 
diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S53.html b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S53.html index cb10a9c09..4fe5b539b 100644 --- a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S53.html +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S53.html @@ -1,4 +1,4 @@ -

Avoid the use of Foreach with Arrays

+

Using List instead of Arrays with Foreach save CPU cycles calculations and RAM consumption

Noncompliant Code Example

 		private final Integer[] intArray = new Integer[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
@@ -10,7 +10,7 @@ 

Noncompliant Code Example

Compliant Solution

-		private final List intList = Arrays.asList(new Integer[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
+		private final List<Integer> intList = Arrays.asList(new Integer[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
 
 		for (Integer i : intList) {
 			...
diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S63.html b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S63.html
index 6baa01875..4541614bc 100644
--- a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S63.html
+++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S63.html
@@ -1,4 +1,4 @@
-

Do not unnecessarily assign values to variables

+

Do not unnecessarily assign values to variables. It increase unless RAM memory usage

Noncompliant Code Example

 String var1 = getValue();
diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S67.html b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S67.html
index 738dfb45f..854cd6e8a 100644
--- a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S67.html
+++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S67.html
@@ -1,4 +1,4 @@
-

Use ++i instead of i++

+

The form $i++ creates a temporary variable whereas ++$i does not. It save CPU cycles.

Noncompliant Code Example

 i++
diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S69.html b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S69.html
index 07044d21c..49a79fabc 100644
--- a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S69.html
+++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S69.html
@@ -1,4 +1,4 @@
-

Do not call a function in the declaration of a for-type loop

+

Do not call a function when declaring a for-type loop in order to avoid function calls each iterations. It saves CPU cycles

Noncompliant Code Example

     public void foo() {
diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S69.json b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S69.json
index d51cbccf7..68cabdd39 100644
--- a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S69.json
+++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S69.json
@@ -1,5 +1,5 @@
 {
-  "title": "Do not call a function in the declaration of a for-type loop",
+  "title": "Do not call a function when declaring a for-type loop",
   "type": "CODE_SMELL",
   "status": "ready",
   "remediation": {
diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S72.html b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S72.html
index d62845123..4bb67e113 100644
--- a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S72.html
+++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S72.html
@@ -1,4 +1,4 @@
-

Do not execute an SQL request in a loop

+

Executing SQL queries in loop induced unnecessary calculation by the cpu, RAM usage and network transfert.

Noncompliant Code Example

     public void foo() {
diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S74.html b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S74.html
index d919af7a8..8d977de29 100644
--- a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S74.html
+++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S74.html
@@ -1,4 +1,4 @@
-

Don't use the query SELECT * FROM

+

Databases servers have to solves fileds regarding to schema. Knowing and using the schema save CPU cycles and network transfer.

Noncompliant Code Example

     public void foo() {
diff --git a/src/php-plugin/src/main/java/fr/cnumr/php/MyPhpRules.java b/src/php-plugin/src/main/java/fr/cnumr/php/MyPhpRules.java
index 29393a555..022ac95d7 100644
--- a/src/php-plugin/src/main/java/fr/cnumr/php/MyPhpRules.java
+++ b/src/php-plugin/src/main/java/fr/cnumr/php/MyPhpRules.java
@@ -34,7 +34,7 @@
 public class MyPhpRules implements RulesDefinition, PHPCustomRuleRepository {
 
   public static final String LANGUAGE = "php";
-  public static final String NAME = "MyCompany Custom Repository";
+  public static final String NAME = "Collectif Conception Numérique Responsable";
   public static final String RESOURCE_BASE_PATH = "fr/cnumr/l10n/php/rules/custom";
   public static final String REPOSITORY_KEY = "cnumr-php";
   private static final Set RULE_TEMPLATES_KEY = Collections.emptySet();
diff --git a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S34.html b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S34.html
index ff380b1d0..5444a6196 100644
--- a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S34.html
+++ b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S34.html
@@ -1,7 +1,8 @@
-

Avoid using try-catch-finally statement

+

Inside complex code parts (for exemple multiple loops, complex data constructions...), avoid using try...catch...finally.

+

When an exception is thrown, a variable (the exception itself) is created in a catch block and it's destruction consumes unnecessary CPU cycles and RAM. Prefer using logical tests in this cases.

Noncompliant Code Example

-try // NOK
+try
 {
   $picture = PDF_open_image_file($PDF, "jpeg", $imgFile, "", 0); // This is the original statement, this works on PHP4
 }
diff --git a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S66.html b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S66.html
index 95b8cd396..28e745335 100644
--- a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S66.html
+++ b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S66.html
@@ -1,4 +1,4 @@
-

Avoid using double quote ("), prefer using simple quote (')

+

PHP allows declaring a string with simple or double quotes. Using double quotes allows developers to insert variables which will be substituted during execution. When the string has no variables, using simple quotes avoid PHP to search inexisting variables. It will save CPU cycles consumption.

Noncompliant Code Example

 myFunction("name", "age", "IsStudent");
@@ -10,3 +10,4 @@ 

Compliant Solution

$lastName = 'Hugo'; $concatenatedString = "$lastName is a student";
+ diff --git a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S66.json b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S66.json index 55464b52c..e176285ad 100644 --- a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S66.json +++ b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S66.json @@ -1,5 +1,5 @@ { - "title": "Avoid using double quote", + "title": "Avoid using double quote (\"), prefer using simple quote (')", "type": "CODE_SMELL", "status": "ready", "remediation": { diff --git a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S67.html b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S67.html index bbddbc09d..5b2ffac4f 100644 --- a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S67.html +++ b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S67.html @@ -1,4 +1,4 @@ -

Replace $i++ by ++$i

+

The form $i++ creates a temporary variable whereas ++$i does not. It save CPU cycles.

Noncompliant Code Example

 $i++
diff --git a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S67.json b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S67.json
index 2934198d6..c6b6e9b09 100644
--- a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S67.json
+++ b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S67.json
@@ -1,5 +1,5 @@
 {
-  "title": "Replace $i++ by ++$i",
+  "title": "Use ++i instead of i++",
   "type": "CODE_SMELL",
   "status": "ready",
   "remediation": {
diff --git a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S69.html b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S69.html
index 26be6e5e7..5db857866 100644
--- a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S69.html
+++ b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S69.html
@@ -1,4 +1,4 @@
-

Do not call a function when declaring a for-type loop

+

Do not call a function when declaring a for-type loop in order to avoid function calls each iterations. It saves CPU cycles

Noncompliant Code Example

 for ($i = 0; $i <= foo(); $i++) { // NOK
diff --git a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S72.html b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S72.html
index dd8b7dabf..3b51bdc50 100644
--- a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S72.html
+++ b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S72.html
@@ -1,4 +1,4 @@
-

Do not execute an SQL request in a loop

+

Executing SQL queries in loop induced unnecessary calculation by the cpu, RAM usage and network transfert.

Noncompliant Code Example

     public function foo() {
diff --git a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S74.html b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S74.html
index daf3f389f..0315dcc4a 100644
--- a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S74.html
+++ b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S74.html
@@ -1,4 +1,4 @@
-

Don't use the query SELECT * FROM

+

Databases servers have to solves fileds regarding to schema. Knowing and using the schema save CPU cycles and network transfer.

Noncompliant Code Example

     public function foo() {
diff --git a/src/python-plugin/src/main/java/fr/cnumr/python/CustomPythonRuleRepository.java b/src/python-plugin/src/main/java/fr/cnumr/python/CustomPythonRuleRepository.java
index 2333305c3..2f0282b66 100644
--- a/src/python-plugin/src/main/java/fr/cnumr/python/CustomPythonRuleRepository.java
+++ b/src/python-plugin/src/main/java/fr/cnumr/python/CustomPythonRuleRepository.java
@@ -29,7 +29,7 @@
 
 public class CustomPythonRuleRepository implements RulesDefinition, PythonCustomRuleRepository {
     public static final String LANGUAGE = "py";
-    public static final String NAME = "MyCompany Custom Repository";
+    public static final String NAME = "Collectif Conception Numérique Responsable";
     public static final String RESOURCE_BASE_PATH = "fr/cnumr/l10n/python/rules/python";
     public static final String REPOSITORY_KEY = "cnumr-python";
     private static final Set RULE_TEMPLATES_KEY = Collections.emptySet();
@@ -54,8 +54,7 @@ public String repositoryKey() {
 
     @Override
     public List checkClasses() {
-        return Arrays.asList(NoFunctionCallWhenDeclaringForLoop.class, AvoidTryCatchFinallyCheck.class,
-                AvoidDoubleQuoteCheck.class, AvoidFullSQLRequest.class, AvoidGlobalVariableInFunctionCheck.class);
+        return Arrays.asList(NoFunctionCallWhenDeclaringForLoop.class, AvoidTryCatchFinallyCheck.class, AvoidFullSQLRequest.class, AvoidGlobalVariableInFunctionCheck.class);
     }
 
     private static void setTemplates(NewRepository repository) {
diff --git a/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidDoubleQuoteCheck.java b/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidDoubleQuoteCheck.java
deleted file mode 100644
index 0977fc510..000000000
--- a/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidDoubleQuoteCheck.java
+++ /dev/null
@@ -1,73 +0,0 @@
-package fr.cnumr.python.checks;
-
-import org.sonar.check.Priority;
-import org.sonar.check.Rule;
-import org.sonar.plugins.python.api.PythonSubscriptionCheck;
-import org.sonar.plugins.python.api.SubscriptionContext;
-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 java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-
-@Rule(
-        key = AvoidDoubleQuoteCheck.RULE_KEY,
-        name = "Developpement",
-        description = AvoidDoubleQuoteCheck.DESCRIPTION,
-        priority = Priority.MINOR,
-        tags = {"bug"})
-public class AvoidDoubleQuoteCheck extends PythonSubscriptionCheck {
-
-    public static final String RULE_KEY = "S66";
-    public static final String DESCRIPTION = "Use single quote (') instead of double quote (\")";
-    private static final Map> linesWithIssuesByFile = new HashMap<>();
-
-    @Override
-    public void initialize(Context context) {
-        context.registerSyntaxNodeConsumer(Tree.Kind.STRING_LITERAL, this::visitNodeString);
-    }
-
-    public void visitNodeString(SubscriptionContext ctx) {
-        StringLiteral stringLiteral = (StringLiteral) ctx.syntaxNode();
-        stringLiteral.stringElements().forEach(stringElement -> {
-            checkIssue(stringElement, ctx);
-        });
-    }
-
-    public void checkIssue(StringElement stringElement, SubscriptionContext ctx) {
-        if (lineAlreadyHasThisIssue(stringElement, ctx)) return;
-        if (stringElement.value().indexOf("\"") == 0 && stringElement.value().lastIndexOf("\"") == stringElement.value().length() - 1) {
-            repport(stringElement, ctx);
-            return;
-        }
-    }
-
-    private void repport(StringElement stringElement, SubscriptionContext ctx) {
-        if (stringElement.firstToken() != null) {
-            final String classname = ctx.pythonFile().fileName();
-            final int line = stringElement.firstToken().line();
-            if (!linesWithIssuesByFile.containsKey(classname)) {
-                linesWithIssuesByFile.put(classname, new ArrayList<>());
-            }
-            linesWithIssuesByFile.get(classname).add(line);
-        }
-        ctx.addIssue(stringElement, DESCRIPTION);
-    }
-
-    private boolean lineAlreadyHasThisIssue(StringElement stringElement, SubscriptionContext ctx) {
-        if (stringElement.firstToken() != null) {
-            final String filename = ctx.pythonFile().fileName();
-            final int line = stringElement.firstToken().line();
-
-            return linesWithIssuesByFile.containsKey(filename)
-                    && linesWithIssuesByFile.get(filename).contains(line);
-        }
-
-        return false;
-    }
-
-
-}
\ No newline at end of file
diff --git a/src/python-plugin/src/main/java/fr/cnumr/python/checks/NoFunctionCallWhenDeclaringForLoop.java b/src/python-plugin/src/main/java/fr/cnumr/python/checks/NoFunctionCallWhenDeclaringForLoop.java
index 210d2f53e..5a2911ad8 100644
--- a/src/python-plugin/src/main/java/fr/cnumr/python/checks/NoFunctionCallWhenDeclaringForLoop.java
+++ b/src/python-plugin/src/main/java/fr/cnumr/python/checks/NoFunctionCallWhenDeclaringForLoop.java
@@ -18,7 +18,7 @@
 public class NoFunctionCallWhenDeclaringForLoop extends PythonSubscriptionCheck {
 
     public static final String RULE_KEY = "S69";
-    public static final String DESCRIPTION = "Do not call a function in the declaration of a for-type loop";
+    public static final String DESCRIPTION = "Do not call a function when declaring a for-type loop";
 
     @Override
     public void initialize(Context context) {
diff --git a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/D4.html b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/D4.html
index f4d820293..812ad2886 100644
--- a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/D4.html
+++ b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/D4.html
@@ -1,11 +1,11 @@
-

Eviter d'utiliser des variables globales directement

+

When function calls global variables, a lot a CPU cycles is consumed

Noncompliant Code Example

 global_var = 'foo'
 def print_global_var_details():
     print(len(global_var)) # Noncompliant
-    print('Global var : ', global_var) # Noncompliant {{Use local variable
-    print('Global var : ' + global_var) # Noncompliant {{Use local variable
+    print('Global var : ', global_var) # Noncompliant
+    print('Global var : ' + global_var) # Noncompliant
 print_global_var_details()
 

Compliant Solution

diff --git a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/D4.json b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/D4.json index 5d2e79adb..0f6c9be50 100644 --- a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/D4.json +++ b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/D4.json @@ -1,5 +1,5 @@ { - "title": "Ne pas appeler de variable globale directement dans les fonctions", + "title": "Do not call global variables directly inside functions", "type": "CODE_SMELL", "status": "ready", "remediation": { diff --git a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S34.html b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S34.html index 3d1aca04c..e72e14b5b 100644 --- a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S34.html +++ b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S34.html @@ -1,4 +1,6 @@ -

Eviter d'utiliser try-catch-finally

+

Inside complex code parts (for exemple multiple loops, complex data constructions...), avoid using try...catch...finally. +

When an exception is thrown, a variable (the exception itself) is created in a catch block and it's destruction consumes unnecessary CPU cycles and RAM. Prefer using logical tests in this cases.

+

Noncompliant Code Example

 try:
diff --git a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S34.json b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S34.json
index e3718d9f9..72a37f621 100644
--- a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S34.json
+++ b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S34.json
@@ -1,5 +1,5 @@
 {
-  "title": "Ne pas appeler de fonction dans la déclaration d’une boucle de type for",
+  "title": "Avoid using try-catch-finally statement",
   "type": "CODE_SMELL",
   "status": "ready",
   "remediation": {
diff --git a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S66.html b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S66.html
deleted file mode 100644
index 6773f86bc..000000000
--- a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S66.html
+++ /dev/null
@@ -1,13 +0,0 @@
-

Utiliser la simple côte (') au lieu du guillemet (")

-

Noncompliant Code Example

-
-print("foo")
-myvalue = "foo"
-
-
-

Compliant Solution

-
-print('foo')
-myvalue = 'foo'
-
-
diff --git a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S66.json b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S66.json deleted file mode 100644 index 1fd95da11..000000000 --- a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S66.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "title": "Utiliser la simple côte (') au lieu du guillemet (\")", - "type": "CODE_SMELL", - "status": "ready", - "remediation": { - "func": "Constant\/Issue", - "constantCost": "5min" - }, - "tags": [ - "eco-conception" - ], - "defaultSeverity": "Minor" -} \ No newline at end of file diff --git a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S69.json b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S69.json index e3718d9f9..68cabdd39 100644 --- a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S69.json +++ b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S69.json @@ -1,5 +1,5 @@ { - "title": "Ne pas appeler de fonction dans la déclaration d’une boucle de type for", + "title": "Do not call a function when declaring a for-type loop", "type": "CODE_SMELL", "status": "ready", "remediation": { diff --git a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S74.html b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S74.html index d919af7a8..8d977de29 100644 --- a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S74.html +++ b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S74.html @@ -1,4 +1,4 @@ -

Don't use the query SELECT * FROM

+

Databases servers have to solves fileds regarding to schema. Knowing and using the schema save CPU cycles and network transfer.

Noncompliant Code Example

     public void foo() {
diff --git a/src/python-plugin/src/test/java/fr/cnumr/python/CustomPythonRuleRepositoryTest.java b/src/python-plugin/src/test/java/fr/cnumr/python/CustomPythonRuleRepositoryTest.java
index b9b20dbbc..80c6ff227 100644
--- a/src/python-plugin/src/test/java/fr/cnumr/python/CustomPythonRuleRepositoryTest.java
+++ b/src/python-plugin/src/test/java/fr/cnumr/python/CustomPythonRuleRepositoryTest.java
@@ -33,7 +33,7 @@ public void test_rule_repository() {
     customPythonRuleRepository.define(context);
     assertThat(customPythonRuleRepository.repositoryKey()).isEqualTo(CustomPythonRuleRepository.REPOSITORY_KEY);
     assertThat(context.repositories()).hasSize(1).extracting("key").containsExactly(customPythonRuleRepository.repositoryKey());
-    assertThat(context.repositories().get(0).rules()).hasSize(5);
-    assertThat(customPythonRuleRepository.checkClasses()).hasSize(5);
+    assertThat(context.repositories().get(0).rules()).hasSize(4);
+    assertThat(customPythonRuleRepository.checkClasses()).hasSize(4);
   }
 }
diff --git a/src/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidDoubleQuoteCheckTest.java b/src/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidDoubleQuoteCheckTest.java
deleted file mode 100644
index b56e9b7b4..000000000
--- a/src/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidDoubleQuoteCheckTest.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package fr.cnumr.python.checks;
-
-import org.junit.Test;
-import org.sonar.python.checks.utils.PythonCheckVerifier;
-
-public class AvoidDoubleQuoteCheckTest {
-
-    @Test
-    public void test() {
-        PythonCheckVerifier.verify("src/test/resources/checks/avoidDoubleQuote.py", new AvoidDoubleQuoteCheck());
-    }
-}
diff --git a/src/python-plugin/src/test/resources/checks/avoidDoubleQuote.py b/src/python-plugin/src/test/resources/checks/avoidDoubleQuote.py
deleted file mode 100644
index 360ff284b..000000000
--- a/src/python-plugin/src/test/resources/checks/avoidDoubleQuote.py
+++ /dev/null
@@ -1,30 +0,0 @@
-def displayMessage(argument1, argument2, argument3):
-    print(argument1+" "+argument2+" "+argument3) # Noncompliant {{Use single quote (') instead of double quote (")}}
-
-# function call
-displayMessage("Geeks", "4", "Geeks") # Noncompliant {{Use single quote (') instead of double quote (")}}
-
-
-
-
-
-print("foo") # Noncompliant {{Use single quote (') instead of double quote (")}}
-
-
-
-print('faa')
-
-
-
-
-print(e)
-
-
-print(6)
-
-
-print('"Rien de grand ne s\'est accompli dans le monde sans passion." - Georg Wilhelm Friedrich Hegel')
-
-myvalue = "foo" # Noncompliant {{Use single quote (') instead of double quote (")}}
-
-myvalue = 'foo'
\ No newline at end of file
diff --git a/src/python-plugin/src/test/resources/checks/noFunctionCallWhenDeclaringForLoop.py b/src/python-plugin/src/test/resources/checks/noFunctionCallWhenDeclaringForLoop.py
index 4cc39dc0d..a3755d3e3 100644
--- a/src/python-plugin/src/test/resources/checks/noFunctionCallWhenDeclaringForLoop.py
+++ b/src/python-plugin/src/test/resources/checks/noFunctionCallWhenDeclaringForLoop.py
@@ -1,7 +1,7 @@
 def my_function():
     return 6
 
-for i in my_function(): # Noncompliant {{Do not call a function in the declaration of a for-type loop}}
+for i in my_function(): # Noncompliant {{Do not call a function when declaring a for-type loop}}
     print("Test")
     my_function()
     pass
diff --git a/src/xml-plugin/src/main/java/fr/cnumr/xml/MyXmlRules.java b/src/xml-plugin/src/main/java/fr/cnumr/xml/MyXmlRules.java
index e54090e06..f0265c021 100644
--- a/src/xml-plugin/src/main/java/fr/cnumr/xml/MyXmlRules.java
+++ b/src/xml-plugin/src/main/java/fr/cnumr/xml/MyXmlRules.java
@@ -33,7 +33,7 @@
 public class MyXmlRules implements RulesDefinition {
 
 	public static final String LANGUAGE = "xml";
-	public static final String NAME = "MyCompany Custom Repository";
+	public static final String NAME = "Collectif Conception Numérique Responsable";
 	public static final String RESOURCE_BASE_PATH = "fr/cnumr/l10n/xml/rules/custom";
 	public static final String REPOSITORY_KEY = "cnumr-xml";
 	private static final Set RULE_TEMPLATES_KEY = Collections.emptySet();

From 2f48b68df114b10165e8991ad6191a9de66cb51c Mon Sep 17 00:00:00 2001
From: Jules Delecour <72793427+jules-delecour-dav@users.noreply.github.com>
Date: Thu, 23 Jun 2022 17:29:40 +0200
Subject: [PATCH 040/119] update to debug (#140)

* update to debug

* preparing file for real python test (not sure it's the right place) but sure that we can continue to chek AST with non fonctional python code

* Insure that python code is functionnal (we can manualy test it), doing homogeneous tests

* all other file have lowercase in first char

* all other file have lowercase in first char (Oup's registring right filename)

* Updating rules test

Co-authored-by: Vincent Cagnard 
---
 .../python/checks/AvoidSQLRequestInLoop.java  | 74 +++++++++++++++++
 .../AvoidSQLRequestInLoopCheckTest.java       | 12 +++
 .../src/test/resources/checks/.gitignore      |  1 +
 .../checks/avoidSQLRequestInLoopCheck.py      | 83 +++++++++++++++++++
 .../src/test/resources/checks/init_dbtest.sql | 34 ++++++++
 .../src/test/resources/checks/my.conf.sample  |  5 ++
 6 files changed, 209 insertions(+)
 create mode 100644 src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidSQLRequestInLoop.java
 create mode 100644 src/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidSQLRequestInLoopCheckTest.java
 create mode 100644 src/python-plugin/src/test/resources/checks/.gitignore
 create mode 100644 src/python-plugin/src/test/resources/checks/avoidSQLRequestInLoopCheck.py
 create mode 100644 src/python-plugin/src/test/resources/checks/init_dbtest.sql
 create mode 100644 src/python-plugin/src/test/resources/checks/my.conf.sample

diff --git a/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidSQLRequestInLoop.java b/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidSQLRequestInLoop.java
new file mode 100644
index 000000000..10e7c38e1
--- /dev/null
+++ b/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidSQLRequestInLoop.java
@@ -0,0 +1,74 @@
+package fr.cnumr.python.checks;
+
+import org.sonar.check.Priority;
+import org.sonar.check.Rule;
+import org.sonar.plugins.python.api.PythonSubscriptionCheck;
+import org.sonar.plugins.python.api.SubscriptionContext;
+import org.sonar.plugins.python.api.tree.*;
+
+import java.util.*;
+import java.lang.*;
+
+@Rule(
+    key = "S64",
+    name = "Developpement",
+    description = AvoidSQLRequestInLoop.MESSAGERULE,
+    priority = Priority.MINOR,
+    tags = {"bug"}
+)
+
+public class AvoidSQLRequestInLoop extends PythonSubscriptionCheck {
+
+    public static final String MESSAGERULE = "Avoid perform an SQL query inside a loop";
+    private static final Map> linesWithIssuesByFile = new HashMap<>();
+
+    @Override
+    public void initialize(Context context) {
+        context.registerSyntaxNodeConsumer(Tree.Kind.FOR_STMT, ctx -> {
+            System.out.println("FOR_STMT");
+            visitLoopNode(((ForStatement) ctx.syntaxNode()).body(), ctx);
+        });
+        context.registerSyntaxNodeConsumer(Tree.Kind.WHILE_STMT, ctx -> {
+            System.out.println("WHILE_STMT");
+            visitLoopNode(((WhileStatement) ctx.syntaxNode()).body(), ctx);
+        });
+    }
+
+    private void visitLoopNode(StatementList list, SubscriptionContext ctx) {
+        for (Statement a: list.statements()) {
+            if (a.getKind().equals(Tree.Kind.EXPRESSION_STMT)) {
+                ExpressionStatement expression = (ExpressionStatement) a;
+                for (Expression i: expression.expressions()) {
+                    if (i.is(Tree.Kind.CALL_EXPR))
+                        visitCallExpressionNode((CallExpression) i, ctx);
+                }
+            }
+        }
+    }
+
+    private void visitCallExpressionNode(CallExpression ce, SubscriptionContext ctx) {
+        for (Tree ele : ce.callee().children()) {
+            if (ele.getKind().equals(Tree.Kind.NAME)) {
+                Name name = (Name) ele;
+                if (name.name().equals("execute")) {    
+                    for (Argument a: ce.arguments()) {
+                        if (checkLitteralInTree((Tree) a))
+                            ctx.addIssue(ce, MESSAGERULE);
+                    }
+                }
+            }
+        }
+    }
+
+    private boolean checkLitteralInTree(Tree t) {
+        for (Tree tc : t.children()) {
+            if (tc.is(Tree.Kind.STRING_LITERAL)) {
+                if (((StringLiteral) tc).trimmedQuotesValue().toUpperCase().contains("SELECT"))
+                    return true;
+            }
+            return checkLitteralInTree(tc);
+        }
+        return false;
+    }
+
+}
diff --git a/src/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidSQLRequestInLoopCheckTest.java b/src/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidSQLRequestInLoopCheckTest.java
new file mode 100644
index 000000000..42c43c427
--- /dev/null
+++ b/src/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidSQLRequestInLoopCheckTest.java
@@ -0,0 +1,12 @@
+package fr.cnumr.python.checks;
+
+import org.junit.Test;
+import org.sonar.python.checks.utils.PythonCheckVerifier;
+
+public class AvoidSQLRequestInLoopCheckTest {
+
+    @Test
+    public void test() {
+        PythonCheckVerifier.verify("src/test/resources/checks/avoidSQLRequestInLoopCheck.py", new AvoidSQLRequestInLoop());
+    }
+}
diff --git a/src/python-plugin/src/test/resources/checks/.gitignore b/src/python-plugin/src/test/resources/checks/.gitignore
new file mode 100644
index 000000000..b6b51e9bb
--- /dev/null
+++ b/src/python-plugin/src/test/resources/checks/.gitignore
@@ -0,0 +1 @@
+my.conf
diff --git a/src/python-plugin/src/test/resources/checks/avoidSQLRequestInLoopCheck.py b/src/python-plugin/src/test/resources/checks/avoidSQLRequestInLoopCheck.py
new file mode 100644
index 000000000..7f98cd548
--- /dev/null
+++ b/src/python-plugin/src/test/resources/checks/avoidSQLRequestInLoopCheck.py
@@ -0,0 +1,83 @@
+import mysql.connector
+
+
+class AvoidSQLRequestInLoopCheck:
+    maxrows = 20
+
+    def testWithNoLoop(self):
+        try :
+            db = mysql.connector.connect(option_files='my.conf', use_pure=True)
+            cursor = db.cursor(dictionary=True)
+
+            cursor.execute('SELECT id, name FROM users LIMIT %(limit)s', {'limit': self.maxrows})
+            for row in cursor.fetchall():
+                print("{}: {}".format(row['id'], row['name']))
+
+            cursor.close()
+            db.close()
+        except mysql.connector.Error as err:
+            print("Got an exception: {}".format(err))
+            db.close()
+
+    def testWithForLoop(self):
+        try:
+            db = mysql.connector.connect(option_files='my.conf', use_pure=True)
+            cursor = db.cursor(dictionary=True)
+
+            for i in range(0, self.maxrows):
+                cursor.execute("SELECT id, name FROM users WHERE id = %(id)s", {'id': i+1}) #Noncompliant
+                for row in cursor.fetchall():
+                    print("{}: {}".format(row['id'], row['name']))
+
+            cursor.close()
+            db.close()
+        except mysql.connector.Error as err:
+            print("Got an exception: {}".format(err))
+            db.close()
+
+    def testWithWhileLoop(self):
+        try:
+            db = mysql.connector.connect(option_files='my.conf', use_pure=True)
+            cursor = db.cursor(dictionary=True)
+
+            i = 0
+            while i < self.maxrows:
+                cursor.execute("SELECT id, name FROM users WHERE id = %(id)s", {'id': i+1}) #Noncompliant
+                for row in cursor.fetchall():
+                    print("name: {}".format(row['name']))
+                i += 1
+
+            cursor.close()
+            db.close()
+        except mysql.connector.Error as err:
+            print("Got an exception: {}".format(err))
+            db.close()
+
+    def testWithWhileLoopUpdate(self):
+        try:
+            db = mysql.connector.connect(option_files='my.conf', use_pure=True)
+            cursor=db.cursor()
+
+            i = 0
+            while i < self.maxrows:
+                cursor.execute('UPDATE users set name=%(name)s where id=%(id)s', {'name': "anonymous", 'id': i+1})
+                i+=1
+            db.commit()
+
+            cursor.close()
+            db.close()
+        except mysql.connector.Error as err:
+            print("Got an exception: {}".format(err))
+            db.close()
+
+if __name__ == '__main__':
+  test = AvoidSQLRequestInLoopCheck()
+
+  print("testWithNoLoop")
+  test.testWithNoLoop()
+  print("testWithForLoop")
+  test.testWithForLoop()
+  print("testWithWhileLoop")
+  test.testWithWhileLoop()
+  print("testWithWhileLoopUpdate")
+  test.testWithWhileLoopUpdate()
diff --git a/src/python-plugin/src/test/resources/checks/init_dbtest.sql b/src/python-plugin/src/test/resources/checks/init_dbtest.sql
new file mode 100644
index 000000000..9a7a0a524
--- /dev/null
+++ b/src/python-plugin/src/test/resources/checks/init_dbtest.sql
@@ -0,0 +1,34 @@
+DROP TABLE IF EXISTS users;
+
+CREATE TABLE users (
+  id INT NOT NULL AUTO_INCREMENT, 
+  name VARCHAR(255),
+  PRIMARY KEY (id)
+);
+
+INSERT INTO users(name) VALUES('a');
+INSERT INTO users(name) VALUES('b');
+INSERT INTO users(name) VALUES('c');
+INSERT INTO users(name) VALUES('d');
+INSERT INTO users(name) VALUES('e');
+INSERT INTO users(name) VALUES('f');
+INSERT INTO users(name) VALUES('g');
+INSERT INTO users(name) VALUES('h');
+INSERT INTO users(name) VALUES('i');
+INSERT INTO users(name) VALUES('j');
+INSERT INTO users(name) VALUES('k');
+INSERT INTO users(name) VALUES('l');
+INSERT INTO users(name) VALUES('m');
+INSERT INTO users(name) VALUES('n');
+INSERT INTO users(name) VALUES('o');
+INSERT INTO users(name) VALUES('p');
+INSERT INTO users(name) VALUES('q');
+INSERT INTO users(name) VALUES('r');
+INSERT INTO users(name) VALUES('s');
+INSERT INTO users(name) VALUES('t');
+INSERT INTO users(name) VALUES('u');
+INSERT INTO users(name) VALUES('v');
+INSERT INTO users(name) VALUES('w');
+INSERT INTO users(name) VALUES('x');
+INSERT INTO users(name) VALUES('y');
+INSERT INTO users(name) VALUES('z');
diff --git a/src/python-plugin/src/test/resources/checks/my.conf.sample b/src/python-plugin/src/test/resources/checks/my.conf.sample
new file mode 100644
index 000000000..e10dc23bc
--- /dev/null
+++ b/src/python-plugin/src/test/resources/checks/my.conf.sample
@@ -0,0 +1,5 @@
+[client]
+host = localhost
+user = dbtest
+password = dbtest
+database = dbtest

From d72799b107586594f4d57a62ddb96323bbdfa5c0 Mon Sep 17 00:00:00 2001
From: Vincent Cagnard 
Date: Thu, 23 Jun 2022 17:44:41 +0200
Subject: [PATCH 041/119] Hotfix for return rule (SQ bug)

---
 .../java/fr/cnumr/python/checks/AvoidSQLRequestInLoop.java     | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidSQLRequestInLoop.java b/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidSQLRequestInLoop.java
index 10e7c38e1..f18f07d81 100644
--- a/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidSQLRequestInLoop.java
+++ b/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidSQLRequestInLoop.java
@@ -66,7 +66,8 @@ private boolean checkLitteralInTree(Tree t) {
                 if (((StringLiteral) tc).trimmedQuotesValue().toUpperCase().contains("SELECT"))
                     return true;
             }
-            return checkLitteralInTree(tc);
+            if (checkLitteralInTree(tc))
+                    return true;
         }
         return false;
     }

From edffd861b0c5291a5a59ed4ba02e27a0d4462ecd Mon Sep 17 00:00:00 2001
From: Vincent Cagnard 
Date: Fri, 24 Jun 2022 07:39:00 +0200
Subject: [PATCH 042/119] HOTFIX removing code smells

---
 .../fr/cnumr/python/checks/AvoidSQLRequestInLoop.java     | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidSQLRequestInLoop.java b/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidSQLRequestInLoop.java
index f18f07d81..c691d4369 100644
--- a/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidSQLRequestInLoop.java
+++ b/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidSQLRequestInLoop.java
@@ -7,7 +7,6 @@
 import org.sonar.plugins.python.api.tree.*;
 
 import java.util.*;
-import java.lang.*;
 
 @Rule(
     key = "S64",
@@ -20,16 +19,13 @@
 public class AvoidSQLRequestInLoop extends PythonSubscriptionCheck {
 
     public static final String MESSAGERULE = "Avoid perform an SQL query inside a loop";
-    private static final Map> linesWithIssuesByFile = new HashMap<>();
 
     @Override
     public void initialize(Context context) {
         context.registerSyntaxNodeConsumer(Tree.Kind.FOR_STMT, ctx -> {
-            System.out.println("FOR_STMT");
             visitLoopNode(((ForStatement) ctx.syntaxNode()).body(), ctx);
         });
         context.registerSyntaxNodeConsumer(Tree.Kind.WHILE_STMT, ctx -> {
-            System.out.println("WHILE_STMT");
             visitLoopNode(((WhileStatement) ctx.syntaxNode()).body(), ctx);
         });
     }
@@ -52,7 +48,7 @@ private void visitCallExpressionNode(CallExpression ce, SubscriptionContext ctx)
                 Name name = (Name) ele;
                 if (name.name().equals("execute")) {    
                     for (Argument a: ce.arguments()) {
-                        if (checkLitteralInTree((Tree) a))
+                        if (checkLitteralInTree(a))
                             ctx.addIssue(ce, MESSAGERULE);
                     }
                 }
@@ -66,7 +62,7 @@ private boolean checkLitteralInTree(Tree t) {
                 if (((StringLiteral) tc).trimmedQuotesValue().toUpperCase().contains("SELECT"))
                     return true;
             }
-            if (checkLitteralInTree(tc))
+            else if (checkLitteralInTree(tc))
                     return true;
         }
         return false;

From 327981918f94ad15784273b3560d068f00e9be45 Mon Sep 17 00:00:00 2001
From: Vincent Cagnard 
Date: Fri, 24 Jun 2022 08:59:28 +0200
Subject: [PATCH 043/119] HOTFIX removing code smells (again)

---
 .../fr/cnumr/python/checks/AvoidSQLRequestInLoop.java     | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidSQLRequestInLoop.java b/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidSQLRequestInLoop.java
index c691d4369..807a71ad2 100644
--- a/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidSQLRequestInLoop.java
+++ b/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidSQLRequestInLoop.java
@@ -6,8 +6,6 @@
 import org.sonar.plugins.python.api.SubscriptionContext;
 import org.sonar.plugins.python.api.tree.*;
 
-import java.util.*;
-
 @Rule(
     key = "S64",
     name = "Developpement",
@@ -23,10 +21,12 @@ public class AvoidSQLRequestInLoop extends PythonSubscriptionCheck {
     @Override
     public void initialize(Context context) {
         context.registerSyntaxNodeConsumer(Tree.Kind.FOR_STMT, ctx -> {
-            visitLoopNode(((ForStatement) ctx.syntaxNode()).body(), ctx);
+            ForStatement fs = (ForStatement) ctx.syntaxNode();
+            visitLoopNode(fs.body(), ctx);
         });
         context.registerSyntaxNodeConsumer(Tree.Kind.WHILE_STMT, ctx -> {
-            visitLoopNode(((WhileStatement) ctx.syntaxNode()).body(), ctx);
+            WhileStatement ws = (WhileStatement) ctx.syntaxNode();
+            visitLoopNode(ws.body(), ctx);
         });
     }
 

From 7b4425a7a08f78aa9518cd5f1c67816cd290d4d9 Mon Sep 17 00:00:00 2001
From: Jules Delecour <72793427+jules-delecour-dav@users.noreply.github.com>
Date: Fri, 8 Jul 2022 15:36:20 +0200
Subject: [PATCH 044/119] Delete
 sonarqube-plugin-greenit/native-analyzer/android-plugin/src/test/java/io/ecocode/java
 directory

---
 .../ecocode/java/JavaRulesDefinitionTest.java | 215 ------------------
 1 file changed, 215 deletions(-)
 delete mode 100644 sonarqube-plugin-greenit/native-analyzer/android-plugin/src/test/java/io/ecocode/java/JavaRulesDefinitionTest.java

diff --git a/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/test/java/io/ecocode/java/JavaRulesDefinitionTest.java b/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/test/java/io/ecocode/java/JavaRulesDefinitionTest.java
deleted file mode 100644
index bc0debbd0..000000000
--- a/sonarqube-plugin-greenit/native-analyzer/android-plugin/src/test/java/io/ecocode/java/JavaRulesDefinitionTest.java
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * SonarQube Java Custom Rules Example
- * Copyright (C) 2016-2016 SonarSource SA
- * mailto:contact 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 io.ecocode.java;
-
-import org.junit.Test;
-import org.sonar.api.rules.RuleType;
-import org.sonar.api.server.debt.DebtRemediationFunction.Type;
-import org.sonar.api.server.rule.RulesDefinition;
-import org.sonar.api.server.rule.RulesDefinition.Param;
-import org.sonar.api.server.rule.RulesDefinition.Repository;
-import org.sonar.api.server.rule.RulesDefinition.Rule;
-
-import static org.fest.assertions.Assertions.assertThat;
-
-public class JavaRulesDefinitionTest {
-
-  @Test
-  public void test() {
-    JavaRulesDefinition rulesDefinition = new JavaRulesDefinition();
-    RulesDefinition.Context context = new RulesDefinition.Context();
-    rulesDefinition.define(context);
-    RulesDefinition.Repository repository = context.repository(Java.REPOSITORY_KEY);
-
-    assertThat(repository.name()).isEqualTo(Java.REPOSITORY_NAME);
-    assertThat(repository.language()).isEqualTo(Java.KEY);
-    assertThat(repository.rules()).hasSize(JavaCheckList.getChecks().size());
-
-    assertRuleProperties(repository);
-    assertAllRuleParametersHaveDescription(repository);
-  }
-
-  private void assertRuleProperties(Repository repository) {
-    Rule rule = repository.rule("EOPT001");
-    assertThat(rule).isNotNull();
-    assertThat(rule.name()).isEqualTo("Optimized API: Fused Location");
-    assertThat(rule.debtRemediationFunction().type()).isEqualTo(Type.CONSTANT_ISSUE);
-    assertThat(rule.type()).isEqualTo(RuleType.CODE_SMELL);
-
-    Rule bleRule = repository.rule("EOPT002");
-    assertThat(bleRule).isNotNull();
-    assertThat(bleRule.name()).isEqualTo("Optimized API: Bluetooth Low-Energy");
-    assertThat(bleRule.debtRemediationFunction().type()).isEqualTo(Type.CONSTANT_ISSUE);
-    assertThat(bleRule.type()).isEqualTo(RuleType.CODE_SMELL);
-
-    Rule keepScreenOnAddFlagRule = repository.rule("EIDL001");
-    assertThat(keepScreenOnAddFlagRule).isNotNull();
-    assertThat(keepScreenOnAddFlagRule.name()).isEqualTo("Idleness: Keep Screen On (addFlags)");
-    assertThat(keepScreenOnAddFlagRule.debtRemediationFunction().type()).isEqualTo(Type.CONSTANT_ISSUE);
-    assertThat(keepScreenOnAddFlagRule.type()).isEqualTo(RuleType.CODE_SMELL);
-
-    Rule keepScreenOnSetFlagRule = repository.rule("EIDL002");
-    assertThat(keepScreenOnSetFlagRule).isNotNull();
-    assertThat(keepScreenOnSetFlagRule.name()).isEqualTo("Idleness: Keep Screen On (setFlags)");
-    assertThat(keepScreenOnSetFlagRule.debtRemediationFunction().type()).isEqualTo(Type.CONSTANT_ISSUE);
-    assertThat(keepScreenOnSetFlagRule.type()).isEqualTo(RuleType.CODE_SMELL);
-
-    Rule brightnessRule = repository.rule("ESOB002");
-    assertThat(brightnessRule).isNotNull();
-    assertThat(brightnessRule.name()).isEqualTo("Sobriety: Brightness Override");
-    assertThat(brightnessRule.debtRemediationFunction().type()).isEqualTo(Type.CONSTANT_ISSUE);
-    assertThat(brightnessRule.type()).isEqualTo(RuleType.CODE_SMELL);
-
-    Rule internetInTheLoopRule = repository.rule("EBOT001");
-    assertThat(internetInTheLoopRule).isNotNull();
-    assertThat(internetInTheLoopRule.name()).isEqualTo("Bottleneck: Internet In The Loop");
-    assertThat(internetInTheLoopRule.debtRemediationFunction().type()).isEqualTo(Type.CONSTANT_ISSUE);
-    assertThat(internetInTheLoopRule.type()).isEqualTo(RuleType.CODE_SMELL);
-
-    Rule keepCpuOnRule = repository.rule("EIDL004");
-    assertThat(keepCpuOnRule).isNotNull();
-    assertThat(keepCpuOnRule.name()).isEqualTo("Idleness: Keep Cpu On");
-    assertThat(keepCpuOnRule.debtRemediationFunction().type()).isEqualTo(Type.CONSTANT_ISSUE);
-    assertThat(keepCpuOnRule.type()).isEqualTo(RuleType.CODE_SMELL);
-
-    Rule thriftyMotionSensorRule = repository.rule("ESOB001");
-    assertThat(thriftyMotionSensorRule).isNotNull();
-    assertThat(thriftyMotionSensorRule.name()).isEqualTo("Sobriety: Thrifty Motion Sensor");
-    assertThat(thriftyMotionSensorRule.debtRemediationFunction().type()).isEqualTo(Type.CONSTANT_ISSUE);
-    assertThat(thriftyMotionSensorRule.type()).isEqualTo(RuleType.CODE_SMELL);
-
-    Rule wifiMulticastLockRule = repository.rule("EBOT002");
-    assertThat(wifiMulticastLockRule).isNotNull();
-    assertThat(wifiMulticastLockRule.name()).isEqualTo("Bottleneck: Wifi Multicast Lock");
-    assertThat(wifiMulticastLockRule.debtRemediationFunction().type()).isEqualTo(Type.CONSTANT_ISSUE);
-    assertThat(wifiMulticastLockRule.type()).isEqualTo(RuleType.CODE_SMELL);
-
-    Rule cameraLeakRule = repository.rule("ELEA002");
-    assertThat(cameraLeakRule).isNotNull();
-    assertThat(cameraLeakRule.name()).isEqualTo("Leakage: Camera Leak");
-    assertThat(cameraLeakRule.debtRemediationFunction().type()).isEqualTo(Type.CONSTANT_ISSUE);
-    assertThat(cameraLeakRule.type()).isEqualTo(RuleType.CODE_SMELL);
-
-    Rule locationLeakRule = repository.rule("ELEA003");
-    assertThat(locationLeakRule).isNotNull();
-    assertThat(locationLeakRule.name()).isEqualTo("Leakage: Location Leak");
-    assertThat(locationLeakRule.debtRemediationFunction().type()).isEqualTo(Type.CONSTANT_ISSUE);
-    assertThat(locationLeakRule.type()).isEqualTo(RuleType.CODE_SMELL);
-
-    Rule sensorManagerLeakRule = repository.rule("ELEA004");
-    assertThat(sensorManagerLeakRule).isNotNull();
-    assertThat(sensorManagerLeakRule.name()).isEqualTo("Leakage: SensorManager Leak");
-    assertThat(sensorManagerLeakRule.debtRemediationFunction().type()).isEqualTo(Type.CONSTANT_ISSUE);
-    assertThat(sensorManagerLeakRule.type()).isEqualTo(RuleType.CODE_SMELL);
-
-    Rule mediaLeakMediaRecorderLeakRule = repository.rule("ELEA005");
-    assertThat(mediaLeakMediaRecorderLeakRule).isNotNull();
-    assertThat(mediaLeakMediaRecorderLeakRule.name()).isEqualTo("Leakage: Media Leak (MediaRecorder)");
-    assertThat(mediaLeakMediaRecorderLeakRule.debtRemediationFunction().type()).isEqualTo(Type.CONSTANT_ISSUE);
-    assertThat(mediaLeakMediaRecorderLeakRule.type()).isEqualTo(RuleType.CODE_SMELL);
-
-    Rule mediaLeakMediaPlayerLeakRule = repository.rule("ELEA006");
-    assertThat(mediaLeakMediaPlayerLeakRule).isNotNull();
-    assertThat(mediaLeakMediaPlayerLeakRule.name()).isEqualTo("Leakage: Media Leak (MediaPlayer)");
-    assertThat(mediaLeakMediaPlayerLeakRule.debtRemediationFunction().type()).isEqualTo(Type.CONSTANT_ISSUE);
-    assertThat(mediaLeakMediaPlayerLeakRule.type()).isEqualTo(RuleType.CODE_SMELL);
-
-    Rule durableWakeLockRule = repository.rule("EIDL006");
-    assertThat(durableWakeLockRule).isNotNull();
-    assertThat(durableWakeLockRule.name()).isEqualTo("Idleness: Durable Wake Lock");
-    assertThat(durableWakeLockRule.debtRemediationFunction().type()).isEqualTo(Type.CONSTANT_ISSUE);
-    assertThat(durableWakeLockRule.type()).isEqualTo(RuleType.CODE_SMELL);
-
-    Rule rigidAlarmSetRepeatingRule = repository.rule("EIDL007");
-    assertThat(rigidAlarmSetRepeatingRule).isNotNull();
-    assertThat(rigidAlarmSetRepeatingRule.name()).isEqualTo("Idleness: Rigid Alarm");
-    assertThat(rigidAlarmSetRepeatingRule.debtRemediationFunction().type()).isEqualTo(Type.CONSTANT_ISSUE);
-    assertThat(rigidAlarmSetRepeatingRule.type()).isEqualTo(RuleType.CODE_SMELL);
-
-    Rule continuousRenderingRule = repository.rule("EIDL008");
-    assertThat(continuousRenderingRule).isNotNull();
-    assertThat(continuousRenderingRule.name()).isEqualTo("Idleness: Continuous Rendering");
-    assertThat(continuousRenderingRule.debtRemediationFunction().type()).isEqualTo(Type.CONSTANT_ISSUE);
-    assertThat(continuousRenderingRule.type()).isEqualTo(RuleType.CODE_SMELL);
-
-    Rule keepVoiceAwakeRule = repository.rule("EIDL009");
-    assertThat(keepVoiceAwakeRule).isNotNull();
-    assertThat(keepVoiceAwakeRule.name()).isEqualTo("Idleness: Keep Voice Awake");
-    assertThat(keepVoiceAwakeRule.debtRemediationFunction().type()).isEqualTo(Type.CONSTANT_ISSUE);
-    assertThat(keepVoiceAwakeRule.type()).isEqualTo(RuleType.CODE_SMELL);
-
-    Rule thriftyGeolocationMinTimeRule = repository.rule("ESOB005");
-    assertThat(thriftyGeolocationMinTimeRule).isNotNull();
-    assertThat(thriftyGeolocationMinTimeRule.name()).isEqualTo("Sobriety: Thrifty Geolocation (minTime)");
-    assertThat(thriftyGeolocationMinTimeRule.debtRemediationFunction().type()).isEqualTo(Type.CONSTANT_ISSUE);
-    assertThat(thriftyGeolocationMinTimeRule.type()).isEqualTo(RuleType.CODE_SMELL);
-
-    Rule thriftyBluetoothLowEnergySetAdvertiseMode = repository.rule("ESOB007");
-    assertThat(thriftyBluetoothLowEnergySetAdvertiseMode).isNotNull();
-    assertThat(thriftyBluetoothLowEnergySetAdvertiseMode.name()).isEqualTo("Sobriety: Thrifty Bluetooth Low Energy (setAdvertiseMode)");
-    assertThat(thriftyBluetoothLowEnergySetAdvertiseMode.debtRemediationFunction().type()).isEqualTo(Type.CONSTANT_ISSUE);
-    assertThat(thriftyBluetoothLowEnergySetAdvertiseMode.type()).isEqualTo(RuleType.CODE_SMELL);
-
-    Rule thriftyBluetoothLowEnergyRequestConnectionPriority = repository.rule("ESOB008");
-    assertThat(thriftyBluetoothLowEnergyRequestConnectionPriority).isNotNull();
-    assertThat(thriftyBluetoothLowEnergyRequestConnectionPriority.name()).isEqualTo("Sobriety: Thrifty Bluetooth Low Energy (requestConnectionPriority)");
-    assertThat(thriftyBluetoothLowEnergyRequestConnectionPriority.debtRemediationFunction().type()).isEqualTo(Type.CONSTANT_ISSUE);
-    assertThat(thriftyBluetoothLowEnergyRequestConnectionPriority.type()).isEqualTo(RuleType.CODE_SMELL);
-
-    Rule thriftyGeolocationMinDistanceRule = repository.rule("ESOB010");
-    assertThat(thriftyGeolocationMinDistanceRule).isNotNull();
-    assertThat(thriftyGeolocationMinDistanceRule.name()).isEqualTo("Sobriety: Thrifty Geolocation (minDistance)");
-    assertThat(thriftyGeolocationMinDistanceRule.debtRemediationFunction().type()).isEqualTo(Type.CONSTANT_ISSUE);
-    assertThat(thriftyGeolocationMinDistanceRule.type()).isEqualTo(RuleType.CODE_SMELL);
-
-    Rule vibrationFreeRule = repository.rule("ESOB011");
-    assertThat(vibrationFreeRule).isNotNull();
-    assertThat(vibrationFreeRule.name()).isEqualTo("Sobriety: Vibration Free");
-    assertThat(vibrationFreeRule.debtRemediationFunction().type()).isEqualTo(Type.CONSTANT_ISSUE);
-    assertThat(vibrationFreeRule.type()).isEqualTo(RuleType.CODE_SMELL);
-
-    Rule thriftyNotification = repository.rule("ESOB012");
-    assertThat(thriftyNotification).isNotNull();
-    assertThat(thriftyNotification.name()).isEqualTo("Sobriety: Thrifty Notification");
-    assertThat(thriftyNotification.debtRemediationFunction().type()).isEqualTo(Type.CONSTANT_ISSUE);
-    assertThat(thriftyNotification.type()).isEqualTo(RuleType.CODE_SMELL);
-
-    Rule torchFreeRule = repository.rule("ESOB013");
-    assertThat(torchFreeRule).isNotNull();
-    assertThat(torchFreeRule.name()).isEqualTo("Sobriety: Torch Free");
-    assertThat(torchFreeRule.debtRemediationFunction().type()).isEqualTo(Type.CONSTANT_ISSUE);
-    assertThat(torchFreeRule.type()).isEqualTo(RuleType.CODE_SMELL);
-
-    Rule chargeAwarenessRule = repository.rule("EPOW004");
-    assertThat(chargeAwarenessRule).isNotNull();
-    assertThat(chargeAwarenessRule.name()).isEqualTo("Power: Charge Awareness");
-    assertThat(chargeAwarenessRule.debtRemediationFunction().type()).isEqualTo(Type.CONSTANT_ISSUE);
-    assertThat(chargeAwarenessRule.type()).isEqualTo(RuleType.CODE_SMELL);
-  }
-
-  private void assertAllRuleParametersHaveDescription(Repository repository) {
-    for (Rule rule : repository.rules()) {
-      for (Param param : rule.params()) {
-        assertThat(param.description()).as("description for " + param.key()).isNotEmpty();
-      }
-    }
-  }
-
-}

From f594f52ce13cf58bd3eab5a257842fc31cb4ec96 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Olivier=20Le=20Goa=C3=ABr?= 
Date: Thu, 25 Aug 2022 16:48:32 +0200
Subject: [PATCH 045/119] fixed start pack link

---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index ec19fd4bf..5a954c133 100644
--- a/README.md
+++ b/README.md
@@ -37,7 +37,7 @@ We are listening to you to make the project progress collectively, and maybe wit
 
 WE NEED YOU !
 
-Here the starter-pack : https://github.com/cnumr/ecoCode/blob/start-pack/hackathon/starter-pack.md
+Here the [starter-pack](./hackathon/starter-pack.md)
 
 ## 🤓 Main contributors
 

From 1321a641fcb9a3fa641e796d175bb4fee542a09b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Olivier=20Le=20Goa=C3=ABr?= 
Date: Thu, 25 Aug 2022 16:56:45 +0200
Subject: [PATCH 046/119] Added academic citation

---
 src/android-plugin/README.md | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/src/android-plugin/README.md b/src/android-plugin/README.md
index eaeffedbe..c2e2ef6cd 100644
--- a/src/android-plugin/README.md
+++ b/src/android-plugin/README.md
@@ -119,3 +119,16 @@ For XML rules:
 ## License
 
 Licensed under the [GNU Lesser General Public License, Version 3.0](https://www.gnu.org/licenses/lgpl.txt)
+
+## How to cite this work?
+
+If you use ecoCode in an academic work we would be really glad if you cite our seminal paper using the following bibtex (to appear):
+```
+@inproceedings{DBLP:conf/ase/LeGoaer2022,
+  author    = {Olivier Le Goaer and Julien Hertout},
+  title     = {ecoCode: a SonarQube Plugin to Remove Energy Smells from Android Projects},
+  booktitle = {{ACM/IEEE} International Conference on Automated Software Engineering,
+               {ASE} '22, Michigan, USA - October 10 - 14, 2022},
+  year      = {2022}
+}
+```

From 04f3869e618017c39d1deeb0b908f985223cf7c8 Mon Sep 17 00:00:00 2001
From: MP-Aubay 
Date: Wed, 7 Sep 2022 17:08:31 +0200
Subject: [PATCH 047/119] fix - Adding 'call' before gradlew to avoid exiting
 before the end (#150)

---
 src/prepare-codenarc.bat | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/prepare-codenarc.bat b/src/prepare-codenarc.bat
index f552a6f87..53bce432e 100644
--- a/src/prepare-codenarc.bat
+++ b/src/prepare-codenarc.bat
@@ -3,7 +3,7 @@ set codenarc_version=2.2.2
 
 REM == Build CodeNarc
 cd codenarc-converter/CodeNarc
-./gradlew build -x test
+call ./gradlew build -x test
 
 REM == Deploy to local repository
 mvn -B install:install-file -Dfile=build/libs/CodeNarc-%codenarc_version%.jar -DgroupId=org.codenarc -DartifactId=CodeNarc -Dversion=%codenarc_version% -Dpackaging=jar

From 251c5e5949baa15c92ac2bccdc8cc19d805fffb1 Mon Sep 17 00:00:00 2001
From: France 
Date: Wed, 21 Sep 2022 17:10:35 +0200
Subject: [PATCH 048/119] francebax: initial commit with tests for rule
 gettingSizeCollectionInLoop

---
 .idea/workspace.xml                           | 33 +++++++++---
 .../main/java/fr/cnumr/java/RulesList.java    |  1 +
 .../AvoidGettingSizeCollectionInLoop.java     | 51 +++++++++++++++++++
 .../AvoidSpringRepositoryCallInLoopCheck.java |  1 +
 .../fr/cnumr/l10n/java/rules/java/GSCIL.html  | 19 +++++++
 .../fr/cnumr/l10n/java/rules/java/GSCIL.json  | 13 +++++
 .../AvoidGettingSizeCollectionInLoopBad.java  | 20 ++++++++
 .../AvoidGettingSizeCollectionInLoopGood.java | 17 +++++++
 .../java/MyJavaFileCheckRegistrarTest.java    |  2 +-
 .../AvoidGettingSizeCollectionInLoopTest.java | 14 +++++
 10 files changed, 164 insertions(+), 7 deletions(-)
 create mode 100644 src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidGettingSizeCollectionInLoop.java
 create mode 100644 src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GSCIL.html
 create mode 100644 src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GSCIL.json
 create mode 100644 src/java-plugin/src/test/files/AvoidGettingSizeCollectionInLoopBad.java
 create mode 100644 src/java-plugin/src/test/files/AvoidGettingSizeCollectionInLoopGood.java
 create mode 100644 src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidGettingSizeCollectionInLoopTest.java

diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 33efe0875..4770f957b 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -1,7 +1,12 @@
 
 
+  
+    
   
-    
+    
+      
+    
     
\ No newline at end of file
diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java b/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java
index bebf41b05..cb29cc4cc 100644
--- a/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java
+++ b/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java
@@ -42,6 +42,7 @@ public static List> getChecks() {
     public static List> getJavaChecks() {
         return Collections.unmodifiableList(Arrays.asList(
                 IncrementCheck.class,
+                AvoidGettingSizeCollectionInLoop.class,
                 NoFunctionCallWhenDeclaringForLoop.class,
                 AvoidSpringRepositoryCallInLoopCheck.class,
                 AvoidSQLRequestInLoop.class,
diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidGettingSizeCollectionInLoop.java b/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidGettingSizeCollectionInLoop.java
new file mode 100644
index 000000000..c4cd16efc
--- /dev/null
+++ b/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidGettingSizeCollectionInLoop.java
@@ -0,0 +1,51 @@
+package fr.cnumr.java.checks;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.sonar.check.Priority;
+import org.sonar.check.Rule;
+import org.sonar.plugins.java.api.IssuableSubscriptionVisitor;
+import org.sonar.plugins.java.api.semantic.MethodMatchers;
+import org.sonar.plugins.java.api.tree.*;
+import org.sonar.plugins.java.api.tree.Tree.Kind;
+
+@Rule(key = "GSCIL",
+        name = "Developpement",
+        description = AvoidGettingSizeCollectionInLoop.MESSAGERULE,
+        priority = Priority.MINOR,
+        tags = {"bug" })
+public class AvoidGettingSizeCollectionInLoop extends IssuableSubscriptionVisitor {
+    protected static final String MESSAGERULE = "Avoid getting the size of the collection in the loop";
+
+
+    private final AvoidGettingSizeCollectionInLoop.AvoidGettingSizeCollectionInLoopVisitor visitorInFile = new AvoidGettingSizeCollectionInLoop.AvoidGettingSizeCollectionInLoopVisitor();
+
+
+    @Override
+    public List nodesToVisit() {
+        return  Arrays.asList(Tree.Kind.FOR_EACH_STATEMENT, Tree.Kind.FOR_STATEMENT, Tree.Kind.WHILE_STATEMENT);
+    }
+
+    @Override
+    public void visitNode(Tree tree) {
+        if (tree instanceof ForStatementTree) {
+            ForStatementTree forStatementTree = (ForStatementTree) tree;
+            ExpressionTree expressionTree = forStatementTree.condition();
+            System.out.println("OK");
+        }
+        tree.accept(visitorInFile);
+    }
+
+    private class AvoidGettingSizeCollectionInLoopVisitor extends BaseTreeVisitor {
+        @Override
+        public void visitForStatement(ForStatementTree tree) {
+            ExpressionTree expression = tree.condition();
+
+
+            super.visitForStatement(tree);
+        }
+
+
+    }
+}
diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidSpringRepositoryCallInLoopCheck.java b/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidSpringRepositoryCallInLoopCheck.java
index f0eb5b8dd..5a8fcf61e 100644
--- a/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidSpringRepositoryCallInLoopCheck.java
+++ b/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidSpringRepositoryCallInLoopCheck.java
@@ -47,5 +47,6 @@ public void visitMethodInvocation(MethodInvocationTree tree) {
                 super.visitMethodInvocation(tree);
             }
         }
+
     }
 }
diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GSCIL.html b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GSCIL.html
new file mode 100644
index 000000000..701cbfbc6
--- /dev/null
+++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GSCIL.html
@@ -0,0 +1,19 @@
+

While iterating through any collection get the size of the collection beforehand and never get it during iteration. The sample is provided below as an illustration which is to be avoided as follows.

+

Noncompliant Code Example

+
+		List<String> objList = getData();
+
+        for (int i = 0; i < objList.size(); i++) {
+            // execute code
+        }
+
+
+

Compliant Solution

+
+        List<String> objList = getData();
+
+        int size = objList.size();
+        for (int i = 0; i < size; i++) {
+            // execute code
+        }
+
diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GSCIL.json b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GSCIL.json new file mode 100644 index 000000000..c0d4f0ccf --- /dev/null +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GSCIL.json @@ -0,0 +1,13 @@ +{ + "title": "Avoid getting the size of the collection in the loop", + "type": "CODE_SMELL", + "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "5min" + }, + "tags": [ + "eco-conception" + ], + "defaultSeverity": "Minor" +} \ No newline at end of file diff --git a/src/java-plugin/src/test/files/AvoidGettingSizeCollectionInLoopBad.java b/src/java-plugin/src/test/files/AvoidGettingSizeCollectionInLoopBad.java new file mode 100644 index 000000000..b9b17cd2f --- /dev/null +++ b/src/java-plugin/src/test/files/AvoidGettingSizeCollectionInLoopBad.java @@ -0,0 +1,20 @@ +package fr.cnumr.java.checks; + +class AvoidGettingSizeCollectionInLoopBad { + AvoidGettingSizeCollectionInLoopBad(AvoidGettingSizeCollectionInLoopBad obj) { + + } + + public void badLoop() + { + Integer[] numbers = new Integer[] { 1, 2, 3 }; + List numberList = new ArrayList(); + numberList.add(10); + numberList.add(20); + numberList.add(10); + + for (int i = 0; i < numberList.size(); i++) { // Noncompliant + System.out.println(numberList[i]); + } + } +} \ No newline at end of file diff --git a/src/java-plugin/src/test/files/AvoidGettingSizeCollectionInLoopGood.java b/src/java-plugin/src/test/files/AvoidGettingSizeCollectionInLoopGood.java new file mode 100644 index 000000000..3a898d79b --- /dev/null +++ b/src/java-plugin/src/test/files/AvoidGettingSizeCollectionInLoopGood.java @@ -0,0 +1,17 @@ +package fr.cnumr.java.checks; + +class AvoidGettingSizeCollectionInLoopGood { + AvoidGettingSizeCollectionInLoopGood(AvoidGettingSizeCollectionInLoopGood obj) { + + } + + public void goodLoop() + { + List numberList = [10, 20, 30, 40, 50]; + + int size = numberList.size(); + for (int i = 0; i < size; i++) { + System.out.println(numberList[i]); + } + } +} \ No newline at end of file diff --git a/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java b/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java index 81ad838e2..2ba76056c 100644 --- a/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java +++ b/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java @@ -32,7 +32,7 @@ void checkNumberRules() { MyJavaFileCheckRegistrar registrar = new MyJavaFileCheckRegistrar(); registrar.register(context); - assertThat(context.checkClasses()).hasSize(7); + assertThat(context.checkClasses()).hasSize(8); assertThat(context.testCheckClasses()).isEmpty(); } diff --git a/src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidGettingSizeCollectionInLoopTest.java b/src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidGettingSizeCollectionInLoopTest.java new file mode 100644 index 000000000..c48a198eb --- /dev/null +++ b/src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidGettingSizeCollectionInLoopTest.java @@ -0,0 +1,14 @@ +package fr.cnumr.java.checks; + +import org.junit.jupiter.api.Test; +import org.sonar.java.checks.verifier.JavaCheckVerifier; + +public class AvoidGettingSizeCollectionInLoopTest { + @Test + void test() { + JavaCheckVerifier.newVerifier() + .onFile("src/test/files/AvoidGettingSizeCollectionInLoopBad.java") + .withCheck(new AvoidGettingSizeCollectionInLoop()) + .verifyIssues(); + } +} \ No newline at end of file From 1c33e4153aacb1580fa2056f05265f62b9621a82 Mon Sep 17 00:00:00 2001 From: France Date: Tue, 27 Sep 2022 12:12:53 +0200 Subject: [PATCH 049/119] france bax: AvoidGettingSizeCollectionInLoop done (with tests) --- .../AvoidGettingSizeCollectionInLoop.java | 33 ++++++++++--------- .../AvoidGettingSizeCollectionInLoopBad.java | 10 +++--- .../AvoidGettingSizeCollectionInLoopGood.java | 11 +++++-- .../AvoidGettingSizeCollectionInLoopTest.java | 4 +++ 4 files changed, 36 insertions(+), 22 deletions(-) diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidGettingSizeCollectionInLoop.java b/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidGettingSizeCollectionInLoop.java index c4cd16efc..324e7fe8c 100644 --- a/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidGettingSizeCollectionInLoop.java +++ b/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidGettingSizeCollectionInLoop.java @@ -1,6 +1,7 @@ package fr.cnumr.java.checks; import java.util.Arrays; +import java.util.Collection; import java.util.List; import org.sonar.check.Priority; @@ -10,6 +11,8 @@ import org.sonar.plugins.java.api.tree.*; import org.sonar.plugins.java.api.tree.Tree.Kind; +import static org.sonar.plugins.java.api.semantic.MethodMatchers.CONSTRUCTOR; + @Rule(key = "GSCIL", name = "Developpement", description = AvoidGettingSizeCollectionInLoop.MESSAGERULE, @@ -17,11 +20,15 @@ tags = {"bug" }) public class AvoidGettingSizeCollectionInLoop extends IssuableSubscriptionVisitor { protected static final String MESSAGERULE = "Avoid getting the size of the collection in the loop"; - - + private static final MethodMatchers SIZE_METHOD = MethodMatchers.or( + MethodMatchers.create() + .ofAnyType() + .names("size", "length") + .withAnyParameters() + .build() + ); private final AvoidGettingSizeCollectionInLoop.AvoidGettingSizeCollectionInLoopVisitor visitorInFile = new AvoidGettingSizeCollectionInLoop.AvoidGettingSizeCollectionInLoopVisitor(); - @Override public List nodesToVisit() { return Arrays.asList(Tree.Kind.FOR_EACH_STATEMENT, Tree.Kind.FOR_STATEMENT, Tree.Kind.WHILE_STATEMENT); @@ -29,23 +36,19 @@ public List nodesToVisit() { @Override public void visitNode(Tree tree) { - if (tree instanceof ForStatementTree) { ForStatementTree forStatementTree = (ForStatementTree) tree; - ExpressionTree expressionTree = forStatementTree.condition(); - System.out.println("OK"); - } - tree.accept(visitorInFile); + BinaryExpressionTree expressionTree = (BinaryExpressionTree) forStatementTree.condition(); + expressionTree.accept(visitorInFile); } private class AvoidGettingSizeCollectionInLoopVisitor extends BaseTreeVisitor { @Override - public void visitForStatement(ForStatementTree tree) { - ExpressionTree expression = tree.condition(); - - - super.visitForStatement(tree); + public void visitMethodInvocation(MethodInvocationTree tree) { + if (SIZE_METHOD.matches(tree.symbol())) { + reportIssue(tree, MESSAGERULE); + } else { + super.visitMethodInvocation(tree); + } } - - } } diff --git a/src/java-plugin/src/test/files/AvoidGettingSizeCollectionInLoopBad.java b/src/java-plugin/src/test/files/AvoidGettingSizeCollectionInLoopBad.java index b9b17cd2f..b4d101dbb 100644 --- a/src/java-plugin/src/test/files/AvoidGettingSizeCollectionInLoopBad.java +++ b/src/java-plugin/src/test/files/AvoidGettingSizeCollectionInLoopBad.java @@ -1,20 +1,22 @@ package fr.cnumr.java.checks; +import java.util.Collection; +import java.util.ArrayList; +import java.util.List; + class AvoidGettingSizeCollectionInLoopBad { - AvoidGettingSizeCollectionInLoopBad(AvoidGettingSizeCollectionInLoopBad obj) { + AvoidGettingSizeCollectionInLoopBad() { } public void badLoop() { - Integer[] numbers = new Integer[] { 1, 2, 3 }; List numberList = new ArrayList(); numberList.add(10); numberList.add(20); - numberList.add(10); for (int i = 0; i < numberList.size(); i++) { // Noncompliant - System.out.println(numberList[i]); + System.out.println("numberList.size()"); } } } \ No newline at end of file diff --git a/src/java-plugin/src/test/files/AvoidGettingSizeCollectionInLoopGood.java b/src/java-plugin/src/test/files/AvoidGettingSizeCollectionInLoopGood.java index 3a898d79b..33d5cbc5d 100644 --- a/src/java-plugin/src/test/files/AvoidGettingSizeCollectionInLoopGood.java +++ b/src/java-plugin/src/test/files/AvoidGettingSizeCollectionInLoopGood.java @@ -1,5 +1,8 @@ package fr.cnumr.java.checks; +import java.util.Collection; +import java.util.ArrayList; +import java.util.List; class AvoidGettingSizeCollectionInLoopGood { AvoidGettingSizeCollectionInLoopGood(AvoidGettingSizeCollectionInLoopGood obj) { @@ -7,11 +10,13 @@ class AvoidGettingSizeCollectionInLoopGood { public void goodLoop() { - List numberList = [10, 20, 30, 40, 50]; + List numberList = new ArrayList(); + numberList.add(10); + numberList.add(20); int size = numberList.size(); - for (int i = 0; i < size; i++) { - System.out.println(numberList[i]); + for (int i = 0; i < size; i++) { // Compliant + System.out.println("numberList.size()"); } } } \ No newline at end of file diff --git a/src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidGettingSizeCollectionInLoopTest.java b/src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidGettingSizeCollectionInLoopTest.java index c48a198eb..d4222ed2a 100644 --- a/src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidGettingSizeCollectionInLoopTest.java +++ b/src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidGettingSizeCollectionInLoopTest.java @@ -10,5 +10,9 @@ void test() { .onFile("src/test/files/AvoidGettingSizeCollectionInLoopBad.java") .withCheck(new AvoidGettingSizeCollectionInLoop()) .verifyIssues(); + JavaCheckVerifier.newVerifier() + .onFile("src/test/files/AvoidGettingSizeCollectionInLoopGood.java") + .withCheck(new AvoidGettingSizeCollectionInLoop()) + .verifyNoIssues(); } } \ No newline at end of file From 38d900fba302034bb4a3a24b64d13d0490ce3c32 Mon Sep 17 00:00:00 2001 From: France Date: Wed, 28 Sep 2022 00:50:31 +0200 Subject: [PATCH 050/119] francebax: done rule AvoidStatementForDMLQueries (with tests) --- .../main/java/fr/cnumr/java/RulesList.java | 1 + .../checks/AvoidStatementForDMLQueries.java | 46 +++++++++++++++++++ .../fr/cnumr/l10n/java/rules/java/SDMLQ1.html | 18 ++++++++ .../fr/cnumr/l10n/java/rules/java/SDMLQ1.json | 13 ++++++ .../files/AvoidStatementForDMLQueries.java | 18 ++++++++ .../java/MyJavaFileCheckRegistrarTest.java | 2 +- .../AvoidStatementForDMLQueriesTest.java | 13 ++++++ 7 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidStatementForDMLQueries.java create mode 100644 src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/SDMLQ1.html create mode 100644 src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/SDMLQ1.json create mode 100644 src/java-plugin/src/test/files/AvoidStatementForDMLQueries.java create mode 100644 src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidStatementForDMLQueriesTest.java diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java b/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java index bebf41b05..420dbef1e 100644 --- a/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java +++ b/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java @@ -43,6 +43,7 @@ public static List> getJavaChecks() { return Collections.unmodifiableList(Arrays.asList( IncrementCheck.class, NoFunctionCallWhenDeclaringForLoop.class, + AvoidStatementForDMLQueries.class, AvoidSpringRepositoryCallInLoopCheck.class, AvoidSQLRequestInLoop.class, AvoidFullSQLRequest.class, diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidStatementForDMLQueries.java b/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidStatementForDMLQueries.java new file mode 100644 index 000000000..951f4e8dc --- /dev/null +++ b/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidStatementForDMLQueries.java @@ -0,0 +1,46 @@ +package fr.cnumr.java.checks; + +import org.sonar.check.Rule; +import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; +import org.sonar.plugins.java.api.semantic.MethodMatchers; +import org.sonar.plugins.java.api.tree.*; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import java.util.Collections; +import java.util.List; + +@Rule(key = "SDMLQ1") +public class AvoidStatementForDMLQueries extends IssuableSubscriptionVisitor { + + private final MethodMatchers EXECUTE_METHOD = MethodMatchers.or( + MethodMatchers.create().ofSubTypes("java.sql.Statement").names("executeUpdate") + .withAnyParameters().build()); + + @Override + public List nodesToVisit() { + return Collections.singletonList(Tree.Kind.METHOD_INVOCATION); + } + + @Override + public void visitNode(Tree tree) { + MethodInvocationTree methodInvocationTree = (MethodInvocationTree) tree; + if (!EXECUTE_METHOD.matches(methodInvocationTree)) + return; + Arguments arguments = methodInvocationTree.arguments(); + if (arguments.size() < 1) + return; + ExpressionTree first = arguments.get(0); + if (first.is(Tree.Kind.STRING_LITERAL)) + { + LiteralTree literalTree = (LiteralTree) first; + String str = literalTree.value(); + String regex = "(SELECT|INSERT INTO|UPDATE|DELETE FROM)\\s(.+,?)+\\s(FROM|VALUES|SET|WHERE)\\s?.*"; + Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE); + Matcher matcher = pattern.matcher(str); + if (matcher.find()) + reportIssue(literalTree, "You must not use Statement for a DML query"); + } + } +} diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/SDMLQ1.html b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/SDMLQ1.html new file mode 100644 index 000000000..f4416989b --- /dev/null +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/SDMLQ1.html @@ -0,0 +1,18 @@ +

Use PreparedStatement instead of Statement

+

Noncompliant Code Example

+
+    public void select() {
+        Statement statement = connection.createStatement();
+        statement.executeUpdate("INSERT INTO persons(id, name) VALUES(2, 'Toto')");  // Noncompliant
+    }
+
+

Compliant Solution

+
+    public void select() {
+        PreparedStatement statement = connection.prepareStatement(INSERT INTO persons(id, name) VALUES(?, ?));
+
+        statement.setInt(1, 2);
+        statement.setString(2, "Toto");
+        statement.executeQuery();
+    }
+
diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/SDMLQ1.json b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/SDMLQ1.json new file mode 100644 index 000000000..8c68b7fd9 --- /dev/null +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/SDMLQ1.json @@ -0,0 +1,13 @@ +{ + "title": "Use PreparedStatement instead of Statement", + "type": "CODE_SMELL", + "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "10min" + }, + "tags": [ + "eco-conception" + ], + "defaultSeverity": "Minor" +} \ No newline at end of file diff --git a/src/java-plugin/src/test/files/AvoidStatementForDMLQueries.java b/src/java-plugin/src/test/files/AvoidStatementForDMLQueries.java new file mode 100644 index 000000000..25da52e7f --- /dev/null +++ b/src/java-plugin/src/test/files/AvoidStatementForDMLQueries.java @@ -0,0 +1,18 @@ +package fr.cnumr.java.checks; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.*; +import java.sql.PreparedStatement; + + + +class AvoidStatementForDMLQueries { + AvoidStatementForDMLQueries(AvoidStatementForDMLQueries mc) { + } + + public void insert() { + Statement statement = connection.createStatement(); + statement.executeUpdate("INSERT INTO persons(id, name) VALUES(2, 'Toto')"); // Noncompliant + } +} \ No newline at end of file diff --git a/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java b/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java index 81ad838e2..2ba76056c 100644 --- a/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java +++ b/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java @@ -32,7 +32,7 @@ void checkNumberRules() { MyJavaFileCheckRegistrar registrar = new MyJavaFileCheckRegistrar(); registrar.register(context); - assertThat(context.checkClasses()).hasSize(7); + assertThat(context.checkClasses()).hasSize(8); assertThat(context.testCheckClasses()).isEmpty(); } diff --git a/src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidStatementForDMLQueriesTest.java b/src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidStatementForDMLQueriesTest.java new file mode 100644 index 000000000..8b56d3aa6 --- /dev/null +++ b/src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidStatementForDMLQueriesTest.java @@ -0,0 +1,13 @@ +package fr.cnumr.java.checks; +import org.junit.jupiter.api.Test; +import org.sonar.java.checks.verifier.CheckVerifier; + +public class AvoidStatementForDMLQueriesTest { + @Test + void test() { + CheckVerifier.newVerifier() + .onFile("src/test/files/AvoidStatementForDMLQueries.java") + .withCheck(new AvoidStatementForDMLQueries()) + .verifyIssues(); + } +} From aa0c1f87e66d864da0285abfc1cd13f4be7fc3c1 Mon Sep 17 00:00:00 2001 From: Jules Delecour Date: Wed, 5 Oct 2022 17:22:33 +0200 Subject: [PATCH 051/119] fix-sonarcloud --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 87b5fd7e7..b5a240ac0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -40,4 +40,4 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - run: mvn -e -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=cnumr_ecoCode -Dsonar.exclusions=**/src/codenarc-converter/**,**/*.groovy,**/src/android-plugin/src/test/**,**/*.dummy + run: mvn -e -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=cnumr_ecoCode -Dsonar.organization=cnumr_1 -Dsonar.exclusions=**/src/codenarc-converter/**,**/*.groovy,**/src/android-plugin/src/test/**,**/*.dummy From ac6677c2d853abef84b0e74c4177c5cfc4249eaa Mon Sep 17 00:00:00 2001 From: Mohamed SALHAOUI <50855585+med-S@users.noreply.github.com> Date: Wed, 19 Oct 2022 08:52:54 +0100 Subject: [PATCH 052/119] Update D4.html Update description to English --- .../main/resources/fr/cnumr/l10n/java/rules/java/D4.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/D4.html b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/D4.html index aa33197ba..91bed4a8e 100644 --- a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/D4.html +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/D4.html @@ -1,9 +1,9 @@

Prefer local variables as parameters

-

A l'appel d'une variable globale, le moteur d'interprétation doit vérifier son existence dans tous les scopes, qu'elle dispose d'une valeur, etc. Passer les variables globales en argument de routines les rend locales dans la fonction, permettant ainsi d'économiser du temps de calcul (cycles CPU). +

When calling a global variable, the interpretation engine must check that it exists in all the scopes, that it has a value, etc. Passing global variables as arguments gives them the statut of local variables inside the function, thus saving computing time (CPU cycles).

-

exemple:
+

example:
var aGlobal = new String('Hello');
function globalLength(){
length = aGlobal.length;
@@ -16,4 +16,4 @@ length = str.length;
console.log(length);
}
- somVarLength(aGlobal);

\ No newline at end of file + somVarLength(aGlobal);

From 04dea124118d3dabe52bb01209bb0a233247ae12 Mon Sep 17 00:00:00 2001 From: Mohamed SALHAOUI <50855585+med-S@users.noreply.github.com> Date: Wed, 19 Oct 2022 09:15:50 +0100 Subject: [PATCH 053/119] Update D4.html Detailed for a concrete example --- .../main/resources/fr/cnumr/l10n/java/rules/java/D4.html | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/D4.html b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/D4.html index 91bed4a8e..a3ee9fe6e 100644 --- a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/D4.html +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/D4.html @@ -3,6 +3,13 @@

When calling a global variable, the interpretation engine must check that it exists in all the scopes, that it has a value, etc. Passing global variables as arguments gives them the statut of local variables inside the function, thus saving computing time (CPU cycles).

+

+CASE 1 (Avoid as possible):
+You are back on the service code. You see that the func1() uses globalVariabl1. Okay, but whats its value by now ? How does it change ? Who mutates the globalVariabl1 before it comes to this function ? What have been the sequence of all these mutations ? You would have no idea. It will be quite difficult to figure all this out. +
+CASE 2 (Recommended):
+You are back to you code, and see that the func0() fetches something and then passes it to func1(param1) as a parameter. You clearly know what the data is, how does it gets here. +


example:
var aGlobal = new String('Hello');
function globalLength(){
From 30e4e334a9c55063669cde4e36f6ebf4abaa94bf Mon Sep 17 00:00:00 2001 From: Mohamed SALHAOUI <50855585+med-S@users.noreply.github.com> Date: Wed, 19 Oct 2022 10:17:11 +0100 Subject: [PATCH 054/119] Update MyJavaFileCheckRegistrarTest.java fixe build fail --- .../test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java b/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java index a659b9c6b..1823b9e32 100644 --- a/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java +++ b/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java @@ -33,7 +33,7 @@ void checkNumberRules() { MyJavaFileCheckRegistrar registrar = new MyJavaFileCheckRegistrar(); registrar.register(context); - assertThat(context.checkClasses()).hasSize(7); + assertThat(context.checkClasses()).hasSize(9); assertThat(context.testCheckClasses()).isEmpty(); } From d9c08504d68b1ed3548cc7ffb5bc762557c788bd Mon Sep 17 00:00:00 2001 From: oussamaLaribi <63214114+oussamaLaribi@users.noreply.github.com> Date: Wed, 19 Oct 2022 11:36:49 +0100 Subject: [PATCH 055/119] Change hasSize parameter from 7 to 8 --- .../test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java b/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java index 81ad838e2..2ba76056c 100644 --- a/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java +++ b/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java @@ -32,7 +32,7 @@ void checkNumberRules() { MyJavaFileCheckRegistrar registrar = new MyJavaFileCheckRegistrar(); registrar.register(context); - assertThat(context.checkClasses()).hasSize(7); + assertThat(context.checkClasses()).hasSize(8); assertThat(context.testCheckClasses()).isEmpty(); } From eeeb53557b6c6c182ead99f2be46cfa9b7d639e3 Mon Sep 17 00:00:00 2001 From: ganeis Date: Wed, 19 Oct 2022 12:49:10 +0200 Subject: [PATCH 056/119] Jaguar - d2 - php (#121) * add d2 php * fix sonar * change NumberOfRuleInRepository from 7 to 8 * Change hasSize parameter from 7 to 8 Co-authored-by: ganeistan Co-authored-by: oussamaLaribi <63214114+oussamaLaribi@users.noreply.github.com> --- src/php-plugin/pom.xml | 24 +++++ .../main/java/fr/cnumr/php/MyPhpRules.java | 2 +- .../UseOfMethodsForBasicOperations.java | 95 +++++++++++++++++++ .../fr/cnumr/l10n/php/rules/custom/D2.html | 9 ++ .../fr/cnumr/l10n/php/rules/custom/D2.json | 13 +++ .../java/fr/cnumr/php/MyPhpRulesTest.java | 2 +- .../UseOfMethodsForBasicOperationsTest.java | 15 +++ .../checks/useOfMethodsForBasicOperations.php | 18 ++++ 8 files changed, 176 insertions(+), 2 deletions(-) create mode 100644 src/php-plugin/src/main/java/fr/cnumr/php/checks/UseOfMethodsForBasicOperations.java create mode 100644 src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/D2.html create mode 100644 src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/D2.json create mode 100644 src/php-plugin/src/test/java/fr/cnumr/php/checks/UseOfMethodsForBasicOperationsTest.java create mode 100644 src/php-plugin/src/test/resources/checks/useOfMethodsForBasicOperations.php diff --git a/src/php-plugin/pom.xml b/src/php-plugin/pom.xml index 6f2bc5e46..9d998b3cc 100644 --- a/src/php-plugin/pom.xml +++ b/src/php-plugin/pom.xml @@ -83,6 +83,30 @@ 1.8 + + org.jacoco + jacoco-maven-plugin + 0.8.7 + + file + false + + + + prepare-agent + + prepare-agent + + + + report + test + + report + + + + diff --git a/src/php-plugin/src/main/java/fr/cnumr/php/MyPhpRules.java b/src/php-plugin/src/main/java/fr/cnumr/php/MyPhpRules.java index 2d1ae43df..7c3832395 100644 --- a/src/php-plugin/src/main/java/fr/cnumr/php/MyPhpRules.java +++ b/src/php-plugin/src/main/java/fr/cnumr/php/MyPhpRules.java @@ -57,7 +57,7 @@ public String repositoryKey() { @Override public ImmutableList checkClasses() { return ImmutableList.of(AvoidUsingGlobalVariablesCheck.class, IncrementCheck.class, AvoidTryCatchFinallyCheck.class, AvoidDoubleQuoteCheck.class, - AvoidFullSQLRequestCheck.class, AvoidSQLRequestInLoopCheck.class, NoFunctionCallWhenDeclaringForLoop.class); + AvoidFullSQLRequestCheck.class, AvoidSQLRequestInLoopCheck.class, NoFunctionCallWhenDeclaringForLoop.class, UseOfMethodsForBasicOperations.class); } @Override diff --git a/src/php-plugin/src/main/java/fr/cnumr/php/checks/UseOfMethodsForBasicOperations.java b/src/php-plugin/src/main/java/fr/cnumr/php/checks/UseOfMethodsForBasicOperations.java new file mode 100644 index 000000000..e843ee486 --- /dev/null +++ b/src/php-plugin/src/main/java/fr/cnumr/php/checks/UseOfMethodsForBasicOperations.java @@ -0,0 +1,95 @@ +package fr.cnumr.php.checks; + +import org.sonar.check.Priority; +import org.sonar.check.Rule; +import org.sonar.plugins.php.api.tree.ScriptTree; +import org.sonar.plugins.php.api.tree.Tree; +import org.sonar.plugins.php.api.tree.declaration.ClassDeclarationTree; +import org.sonar.plugins.php.api.tree.declaration.ClassMemberTree; +import org.sonar.plugins.php.api.tree.declaration.MethodDeclarationTree; +import org.sonar.plugins.php.api.tree.expression.FunctionCallTree; +import org.sonar.plugins.php.api.tree.statement.*; +import org.sonar.plugins.php.api.visitors.PHPSubscriptionCheck; + +import java.util.*; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Collectors; + +@Rule( + key = "D2", + name = "Developpement", + description = UseOfMethodsForBasicOperations.ERROR_MESSAGE, + priority = Priority.MINOR, + tags = {"bug"}) +public class UseOfMethodsForBasicOperations extends PHPSubscriptionCheck { + + protected static final String ERROR_MESSAGE = "Use of methods for basic operations"; + + @Override + public List nodesToVisit() { + return Collections.singletonList(Tree.Kind.FUNCTION_CALL); + } + + @Override + public void visitNode(Tree tree) { + AtomicBoolean contains = new AtomicBoolean(false); + + final FunctionCallTree functionTree = ((FunctionCallTree) tree); + final String functionName = functionTree.callee().toString(); + + final List parents = this.getAllParent(tree, new ArrayList<>()); + + parents.forEach(parent -> { + if(parent.is(Tree.Kind.SCRIPT)) { + + final ScriptTree specific = (ScriptTree) parent; + final List trees = specific.statements(); + + trees.forEach(statement -> { + + if(statement.is(Tree.Kind.CLASS_DECLARATION)) { + + final List methodDeclarations = ((ClassDeclarationTree) statement).members() + .stream() + .filter(member -> member.is(Tree.Kind.METHOD_DECLARATION)) + .map(MethodDeclarationTree.class::cast) + .filter(declarationTree -> this.isFunctionDeclared(declarationTree, functionName)) + .collect(Collectors.toList()); + + if(methodDeclarations != null && !methodDeclarations.isEmpty()) { + contains.set(true); + } + } + }); + } + }); + + if(!contains.get()) { + context().newIssue(this, tree, ERROR_MESSAGE); + } + } + + public boolean isFunctionDeclared(final MethodDeclarationTree method, final String name) { + if(method == null) { + return false; + } + + return method.name().text() + .trim() + .equals(name.trim()); + } + + public List getAllParent(final Tree tree, final List list) { + if(tree == null) + return list; + + final Tree parent = tree.getParent(); + + if(parent == null) + return list; + + list.add(parent); + + return this.getAllParent(parent, list); + } +} diff --git a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/D2.html b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/D2.html new file mode 100644 index 000000000..8b10e7217 --- /dev/null +++ b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/D2.html @@ -0,0 +1,9 @@ +

Use of methods for basic operations

+

Noncompliant Code Example

+
+    $min = min($a, $b); // NOK
+
+

Compliant Solution

+
+    $min = ($a < $b) ? $a : $b; // NOK
+
diff --git a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/D2.json b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/D2.json new file mode 100644 index 000000000..6c998b285 --- /dev/null +++ b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/D2.json @@ -0,0 +1,13 @@ +{ + "title": "Use of methods for basic operations", + "type": "CODE_SMELL", + "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "5min" + }, + "tags": [ + "eco-conception" + ], + "defaultSeverity": "Minor" +} \ No newline at end of file diff --git a/src/php-plugin/src/test/java/fr/cnumr/php/MyPhpRulesTest.java b/src/php-plugin/src/test/java/fr/cnumr/php/MyPhpRulesTest.java index 4fb8302af..8944787ab 100644 --- a/src/php-plugin/src/test/java/fr/cnumr/php/MyPhpRulesTest.java +++ b/src/php-plugin/src/test/java/fr/cnumr/php/MyPhpRulesTest.java @@ -7,7 +7,7 @@ public class MyPhpRulesTest { - private int NumberOfRuleInRepository = 7; + private int NumberOfRuleInRepository = 8; @Test public void rules() { diff --git a/src/php-plugin/src/test/java/fr/cnumr/php/checks/UseOfMethodsForBasicOperationsTest.java b/src/php-plugin/src/test/java/fr/cnumr/php/checks/UseOfMethodsForBasicOperationsTest.java new file mode 100644 index 000000000..34d431f49 --- /dev/null +++ b/src/php-plugin/src/test/java/fr/cnumr/php/checks/UseOfMethodsForBasicOperationsTest.java @@ -0,0 +1,15 @@ +package fr.cnumr.php.checks; + +import org.junit.Test; +import org.sonar.plugins.php.api.tests.PHPCheckTest; +import org.sonar.plugins.php.api.tests.PhpTestFile; + +import java.io.File; + +public class UseOfMethodsForBasicOperationsTest { + + @Test + public void test() throws Exception { + PHPCheckTest.check(new UseOfMethodsForBasicOperations(), new PhpTestFile(new File("src/test/resources/checks/useOfMethodsForBasicOperations.php"))); + } +} diff --git a/src/php-plugin/src/test/resources/checks/useOfMethodsForBasicOperations.php b/src/php-plugin/src/test/resources/checks/useOfMethodsForBasicOperations.php new file mode 100644 index 000000000..d767e3907 --- /dev/null +++ b/src/php-plugin/src/test/resources/checks/useOfMethodsForBasicOperations.php @@ -0,0 +1,18 @@ + \ No newline at end of file From ec62c1e22e11dce503652979984d0c036f425af0 Mon Sep 17 00:00:00 2001 From: Mohamed SALHAOUI <50855585+med-S@users.noreply.github.com> Date: Tue, 25 Oct 2022 10:20:47 +0100 Subject: [PATCH 057/119] Update D1.html --- .../src/main/resources/fr/cnumr/l10n/php/rules/custom/D1.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/D1.html b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/D1.html index dc1b235b5..edf22ff81 100644 --- a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/D1.html +++ b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/D1.html @@ -1,2 +1,2 @@

Avoid using try-catch-finally statement

-

Lorsqu'une exception est levée, une variable (l'exception elle-même) est créée dans le bloc catch et détruite à la fin du bloc. La création de cette variable et sa destruction consomment inutilement des cycle CPU et de la mémoire vive. Il faut mieux lui préférer autant que possible un test logique. +

When an exception is thrown, a variable (the exception itself) is created in the catch block and destroyed at the end of the block. Creating this variable and destroying it consumes CPU cycles and RAM unnecessarily. It is better to prefer a logical test as much as possible.

From 5de3d4e81f510fb3dadfeafb7099b6683c26cdf3 Mon Sep 17 00:00:00 2001 From: Mohamed SALHAOUI <50855585+med-S@users.noreply.github.com> Date: Tue, 25 Oct 2022 10:25:52 +0100 Subject: [PATCH 058/119] Update MyPhpRulesTest.java --- src/php-plugin/src/test/java/fr/cnumr/php/MyPhpRulesTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php-plugin/src/test/java/fr/cnumr/php/MyPhpRulesTest.java b/src/php-plugin/src/test/java/fr/cnumr/php/MyPhpRulesTest.java index 8944787ab..4fb8302af 100644 --- a/src/php-plugin/src/test/java/fr/cnumr/php/MyPhpRulesTest.java +++ b/src/php-plugin/src/test/java/fr/cnumr/php/MyPhpRulesTest.java @@ -7,7 +7,7 @@ public class MyPhpRulesTest { - private int NumberOfRuleInRepository = 8; + private int NumberOfRuleInRepository = 7; @Test public void rules() { From 8b7185bebaff7f0e527ebc0e46b788d324bb7069 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Renault <81814445+bantra7@users.noreply.github.com> Date: Tue, 25 Oct 2022 11:29:38 +0200 Subject: [PATCH 059/119] Add rule D7 Python - Avoid Getters and Setters in class (#101) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add rule D7 Python - Avoid Getters and Setters in class * Add rule D7 Python - Avoid Getters and Setters in class * Add rule D7 Python - Add new tests * D7-PYTHON Ajout de la vérification des setters * Add rule D7 Python - Avoid Getters and Setters in class * Add rule D7 Python - Add new tests * D7-PYTHON Ajout de la vérification des setters * D7 Python - merge two if * Refactoring code to pass sonar * ix sonar issue * Fix sonar issue * Fix sonar issue * fix sonar issue Co-authored-by: oussamaLaribi <63214114+oussamaLaribi@users.noreply.github.com> --- .../python/CustomPythonRuleRepository.java | 4 +- .../python/checks/AvoidGettersAndSetters.java | 76 +++++++++++++++++++ .../fr/cnumr/l10n/python/rules/python/D7.html | 36 +++++++++ .../fr/cnumr/l10n/python/rules/python/D7.json | 13 ++++ .../CustomPythonRuleRepositoryTest.java | 4 +- .../checks/AvoidGettersAndSettersTest.java | 12 +++ .../checks/avoidGettersAndSetters.py | 26 +++++++ 7 files changed, 168 insertions(+), 3 deletions(-) create mode 100644 src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidGettersAndSetters.java create mode 100644 src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/D7.html create mode 100644 src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/D7.json create mode 100644 src/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidGettersAndSettersTest.java create mode 100644 src/python-plugin/src/test/resources/checks/avoidGettersAndSetters.py diff --git a/src/python-plugin/src/main/java/fr/cnumr/python/CustomPythonRuleRepository.java b/src/python-plugin/src/main/java/fr/cnumr/python/CustomPythonRuleRepository.java index 2f0282b66..d35b28954 100644 --- a/src/python-plugin/src/main/java/fr/cnumr/python/CustomPythonRuleRepository.java +++ b/src/python-plugin/src/main/java/fr/cnumr/python/CustomPythonRuleRepository.java @@ -20,6 +20,7 @@ package fr.cnumr.python; + import fr.cnumr.python.checks.*; import org.sonar.api.server.rule.RulesDefinition; import org.sonar.plugins.python.api.PythonCustomRuleRepository; @@ -54,7 +55,8 @@ public String repositoryKey() { @Override public List checkClasses() { - return Arrays.asList(NoFunctionCallWhenDeclaringForLoop.class, AvoidTryCatchFinallyCheck.class, AvoidFullSQLRequest.class, AvoidGlobalVariableInFunctionCheck.class); + return Arrays.asList(NoFunctionCallWhenDeclaringForLoop.class, AvoidTryCatchFinallyCheck.class, + AvoidFullSQLRequest.class, AvoidGlobalVariableInFunctionCheck.class, AvoidGettersAndSetters.class); } private static void setTemplates(NewRepository repository) { diff --git a/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidGettersAndSetters.java b/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidGettersAndSetters.java new file mode 100644 index 000000000..cb44282b2 --- /dev/null +++ b/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidGettersAndSetters.java @@ -0,0 +1,76 @@ +package fr.cnumr.python.checks; + +import java.util.List; +import java.util.stream.Collectors; + +import org.sonar.check.Priority; +import org.sonar.check.Rule; +import org.sonar.plugins.python.api.PythonSubscriptionCheck; +import org.sonar.plugins.python.api.tree.AnyParameter; +import org.sonar.plugins.python.api.tree.AssignmentStatement; +import org.sonar.plugins.python.api.tree.FunctionDef; +import org.sonar.plugins.python.api.tree.ParameterList; +import org.sonar.plugins.python.api.tree.QualifiedExpression; +import org.sonar.plugins.python.api.tree.ReturnStatement; +import org.sonar.plugins.python.api.tree.Statement; +import org.sonar.plugins.python.api.tree.StatementList; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.plugins.python.api.SubscriptionContext; + +@Rule( + key = AvoidGettersAndSetters.RULE_KEY, + name = "Developpement", + description = AvoidGettersAndSetters.DESCRIPTION, + priority = Priority.MINOR, + tags = { "bug" }) +public class AvoidGettersAndSetters extends PythonSubscriptionCheck { + + public static final String RULE_KEY = "D7"; + public static final String DESCRIPTION = "Avoid the use of getters and setters"; + + @Override + public void initialize(Context context) { + context.registerSyntaxNodeConsumer(Tree.Kind.FUNCDEF, ctx -> { + FunctionDef functionDef = (FunctionDef) ctx.syntaxNode(); + StatementList statementList = functionDef.body(); + List statements = statementList.statements(); + if (functionDef.parent().parent().is(Tree.Kind.CLASSDEF)) { + checkAllGetters(statements,functionDef,ctx); + checkAllSetters(statements,functionDef,ctx); + } + }); + } + public void checkAllSetters(List statements,FunctionDef functionDef,SubscriptionContext ctx){ + if(statements.size() == 1 && statements.get(0).is(Tree.Kind.ASSIGNMENT_STMT)){ + AssignmentStatement assignmentStatement = (AssignmentStatement) statements.get(0); + if(checkIfStatementIsQualifiedExpressionAndStartsWithSelfDot((QualifiedExpression) assignmentStatement.children().get(0).children().get(0))){ + // Check if assignedValue is a parameter of the function + ParameterList parameters = functionDef.parameters(); + if(parameters != null && !parameters.all().stream().filter(p -> checkAssignementFromParameter(assignmentStatement, p)).collect(Collectors.toList()).isEmpty()){ + ctx.addIssue(functionDef.defKeyword(), AvoidGettersAndSetters.DESCRIPTION); + } + } + } + } + public void checkAllGetters(List statements,FunctionDef functionDef,SubscriptionContext ctx){ + Statement lastStatement = statements.get(statements.size() - 1); + if (lastStatement.is(Tree.Kind.RETURN_STMT)) { + List returnStatementChildren = ((ReturnStatement) lastStatement).children(); + if (returnStatementChildren.get(1).is(Tree.Kind.QUALIFIED_EXPR) && + checkIfStatementIsQualifiedExpressionAndStartsWithSelfDot((QualifiedExpression) returnStatementChildren.get(1))){ + ctx.addIssue(functionDef.defKeyword(), AvoidGettersAndSetters.DESCRIPTION); + } + } + } + public boolean checkAssignementFromParameter(AssignmentStatement assignmentStatement, AnyParameter parameter){ + String parameterToString = parameter.firstToken().value(); + return assignmentStatement.assignedValue().firstToken().value().equalsIgnoreCase(parameterToString); + } + + public boolean checkIfStatementIsQualifiedExpressionAndStartsWithSelfDot(QualifiedExpression qualifiedExpression){ + List qualifedExpressionChildren = qualifiedExpression.children(); + return qualifedExpressionChildren.size() == 3 && + qualifedExpressionChildren.get(0).firstToken().value().equalsIgnoreCase("self") && + qualifedExpressionChildren.get(1).firstToken().value().equalsIgnoreCase("."); + } +} diff --git a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/D7.html b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/D7.html new file mode 100644 index 000000000..ec24f940d --- /dev/null +++ b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/D7.html @@ -0,0 +1,36 @@ +

Eviter de créer des méthodes getter et setter dans les classes.

+

Noncompliant Code Example

+
+class Client():
+
+    def __init__(self, age):
+        self.age = age
+
+    def get_age(self):
+        return self.age
+
+    def set_age(self, age):
+        self.age = age
+
+client = Client(25)
+client.get_age() # Getter inutile
+client.set_age(25) # Setter inutile
+
+
+

Compliant Solution

+
+class Client():
+
+    def __init__(self, age):
+        self.age = age
+
+    def get_age(self):
+        return self.age
+
+    def set_age(self, age):
+        self.age = age
+
+client = Client(25)
+client.age # Récupérer l'attribut age
+client.age = 26 # Modifier l'attribut age
+
diff --git a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/D7.json b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/D7.json new file mode 100644 index 000000000..e32253fc5 --- /dev/null +++ b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/D7.json @@ -0,0 +1,13 @@ +{ + "title": "Eviter de créer des méthodes getter et setter dans les classes.", + "type": "CODE_SMELL", + "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "5min" + }, + "tags": [ + "eco-conception" + ], + "defaultSeverity": "Minor" + } \ No newline at end of file diff --git a/src/python-plugin/src/test/java/fr/cnumr/python/CustomPythonRuleRepositoryTest.java b/src/python-plugin/src/test/java/fr/cnumr/python/CustomPythonRuleRepositoryTest.java index 80c6ff227..b9b20dbbc 100644 --- a/src/python-plugin/src/test/java/fr/cnumr/python/CustomPythonRuleRepositoryTest.java +++ b/src/python-plugin/src/test/java/fr/cnumr/python/CustomPythonRuleRepositoryTest.java @@ -33,7 +33,7 @@ public void test_rule_repository() { customPythonRuleRepository.define(context); assertThat(customPythonRuleRepository.repositoryKey()).isEqualTo(CustomPythonRuleRepository.REPOSITORY_KEY); assertThat(context.repositories()).hasSize(1).extracting("key").containsExactly(customPythonRuleRepository.repositoryKey()); - assertThat(context.repositories().get(0).rules()).hasSize(4); - assertThat(customPythonRuleRepository.checkClasses()).hasSize(4); + assertThat(context.repositories().get(0).rules()).hasSize(5); + assertThat(customPythonRuleRepository.checkClasses()).hasSize(5); } } diff --git a/src/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidGettersAndSettersTest.java b/src/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidGettersAndSettersTest.java new file mode 100644 index 000000000..a4a265069 --- /dev/null +++ b/src/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidGettersAndSettersTest.java @@ -0,0 +1,12 @@ +package fr.cnumr.python.checks; + +import org.junit.Test; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class AvoidGettersAndSettersTest { + + @Test + public void test() { + PythonCheckVerifier.verify("src/test/resources/checks/avoidGettersAndSetters.py", new AvoidGettersAndSetters()); + } +} diff --git a/src/python-plugin/src/test/resources/checks/avoidGettersAndSetters.py b/src/python-plugin/src/test/resources/checks/avoidGettersAndSetters.py new file mode 100644 index 000000000..e8a3efd1c --- /dev/null +++ b/src/python-plugin/src/test/resources/checks/avoidGettersAndSetters.py @@ -0,0 +1,26 @@ +from datetime import date + +class Client(): + + def __init__(self, age, weight): + self.age = age + self.weight = weight + + def set_age(self, age): # Noncompliant {{Avoid the use of getters and setters}} + self.age = age + + def set_age(self, age2): # Noncompliant {{Avoid the use of getters and setters}} + self.age = age2 + + def get_age_in_five_years(self): + a = Client() + return a.age + + def get_age(self): # Noncompliant {{Avoid the use of getters and setters}} + return self.age + + def is_major(self): + return self.age >= 18 + + def get_weight(self): # Noncompliant {{Avoid the use of getters and setters}} + return self.weight \ No newline at end of file From 9c12c157bc434988f2cf0d1dccba0c5cd871d03f Mon Sep 17 00:00:00 2001 From: Nicolas Le Cam Date: Tue, 25 Oct 2022 11:47:01 +0200 Subject: [PATCH 060/119] ecoCode Challenge: Rule 64-PYTHON (#94) * Add rule 64 - [PYTHON] - Perform an SQL query inside a loop * Expose new rule in repository * Add rule documentation * Chage a test to use a while loop * cancel old test * delete old test AvoidSQLRequestInLoop * Change Size to 6 Co-authored-by: Nicolas Le Cam Co-authored-by: oussamaLaribi <63214114+oussamaLaribi@users.noreply.github.com> --- .../python/CustomPythonRuleRepository.java | 25 +++-- .../python/checks/AvoidSQLRequestInLoop.java | 93 ++++++++++--------- .../cnumr/l10n/python/rules/python/S72.html | 21 +++++ .../cnumr/l10n/python/rules/python/S72.json | 13 +++ .../CustomPythonRuleRepositoryTest.java | 4 +- .../AvoidSQLRequestInLoopCheckTest.java | 12 --- .../checks/AvoidSQLRequestInLoopTest.java | 12 +++ .../resources/checks/avoidSQLRequestInLoop.py | 42 +++++++++ .../checks/avoidSQLRequestInLoopNoImports.py | 26 ++++++ 9 files changed, 180 insertions(+), 68 deletions(-) create mode 100644 src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S72.html create mode 100644 src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S72.json delete mode 100644 src/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidSQLRequestInLoopCheckTest.java create mode 100644 src/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidSQLRequestInLoopTest.java create mode 100644 src/python-plugin/src/test/resources/checks/avoidSQLRequestInLoop.py create mode 100644 src/python-plugin/src/test/resources/checks/avoidSQLRequestInLoopNoImports.py diff --git a/src/python-plugin/src/main/java/fr/cnumr/python/CustomPythonRuleRepository.java b/src/python-plugin/src/main/java/fr/cnumr/python/CustomPythonRuleRepository.java index d35b28954..67a35ea14 100644 --- a/src/python-plugin/src/main/java/fr/cnumr/python/CustomPythonRuleRepository.java +++ b/src/python-plugin/src/main/java/fr/cnumr/python/CustomPythonRuleRepository.java @@ -35,6 +35,13 @@ public class CustomPythonRuleRepository implements RulesDefinition, PythonCustom public static final String REPOSITORY_KEY = "cnumr-python"; private static final Set RULE_TEMPLATES_KEY = Collections.emptySet(); + private static void setTemplates(NewRepository repository) { + RULE_TEMPLATES_KEY.stream() + .map(repository::rule) + .filter(Objects::nonNull) + .forEach(rule -> rule.setTemplate(true)); + } + @Override public void define(Context context) { NewRepository repository = context.createRepository(REPOSITORY_KEY, LANGUAGE).setName(NAME); @@ -55,15 +62,13 @@ public String repositoryKey() { @Override public List checkClasses() { - return Arrays.asList(NoFunctionCallWhenDeclaringForLoop.class, AvoidTryCatchFinallyCheck.class, - AvoidFullSQLRequest.class, AvoidGlobalVariableInFunctionCheck.class, AvoidGettersAndSetters.class); + return Arrays.asList( + AvoidGlobalVariableInFunctionCheck.class, + AvoidFullSQLRequest.class, + AvoidSQLRequestInLoop.class, + AvoidTryCatchFinallyCheck.class, + NoFunctionCallWhenDeclaringForLoop.class, + AvoidGettersAndSetters.class + ); } - - private static void setTemplates(NewRepository repository) { - RULE_TEMPLATES_KEY.stream() - .map(repository::rule) - .filter(Objects::nonNull) - .forEach(rule -> rule.setTemplate(true)); - } - } diff --git a/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidSQLRequestInLoop.java b/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidSQLRequestInLoop.java index 807a71ad2..344164358 100644 --- a/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidSQLRequestInLoop.java +++ b/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidSQLRequestInLoop.java @@ -4,68 +4,73 @@ import org.sonar.check.Rule; import org.sonar.plugins.python.api.PythonSubscriptionCheck; import org.sonar.plugins.python.api.SubscriptionContext; +import org.sonar.plugins.python.api.symbols.Symbol; import org.sonar.plugins.python.api.tree.*; -@Rule( - key = "S64", - name = "Developpement", - description = AvoidSQLRequestInLoop.MESSAGERULE, - priority = Priority.MINOR, - tags = {"bug"} -) +import java.util.*; +@Rule( + key = "S72", + name = "Developpement", + description = AvoidSQLRequestInLoop.MESSAGE_RULE, + priority = Priority.MINOR, + tags = {"bug"}) public class AvoidSQLRequestInLoop extends PythonSubscriptionCheck { + // TODO: Handle ORM lib + private static final List SQL_LIBS = Arrays.asList("cx_Oracle", "mysql.connector", "psycopg2", "pymssql", "pyodbc", "sqlite3"); + + protected static final String MESSAGE_RULE = "Avoid performing SQL queries within a loop"; - public static final String MESSAGERULE = "Avoid perform an SQL query inside a loop"; + private boolean isUsingSqlLib = false; @Override public void initialize(Context context) { - context.registerSyntaxNodeConsumer(Tree.Kind.FOR_STMT, ctx -> { - ForStatement fs = (ForStatement) ctx.syntaxNode(); - visitLoopNode(fs.body(), ctx); - }); - context.registerSyntaxNodeConsumer(Tree.Kind.WHILE_STMT, ctx -> { - WhileStatement ws = (WhileStatement) ctx.syntaxNode(); - visitLoopNode(ws.body(), ctx); - }); + context.registerSyntaxNodeConsumer(Tree.Kind.FILE_INPUT, this::visitFile); + context.registerSyntaxNodeConsumer(Tree.Kind.CALL_EXPR, this::checkCallExpression); } - private void visitLoopNode(StatementList list, SubscriptionContext ctx) { - for (Statement a: list.statements()) { - if (a.getKind().equals(Tree.Kind.EXPRESSION_STMT)) { - ExpressionStatement expression = (ExpressionStatement) a; - for (Expression i: expression.expressions()) { - if (i.is(Tree.Kind.CALL_EXPR)) - visitCallExpressionNode((CallExpression) i, ctx); - } - } + private void visitFile(SubscriptionContext ctx) { + FileInput tree = (FileInput) ctx.syntaxNode(); + SymbolsFromImport visitor = new SymbolsFromImport(); + tree.accept(visitor); + visitor.symbols.stream() + .filter(Objects::nonNull) + .map(Symbol::fullyQualifiedName) + .filter(Objects::nonNull) + .forEach(qualifiedName -> { + if (SQL_LIBS.contains(qualifiedName)) { + isUsingSqlLib = true; + } + }); + } + + private static class SymbolsFromImport extends BaseTreeVisitor { + private Set symbols = new HashSet<>(); + + @Override + public void visitAliasedName(AliasedName aliasedName) { + List names = aliasedName.dottedName().names(); + symbols.add(names.get(names.size() - 1).symbol()); } } + private void checkCallExpression(SubscriptionContext context) { + CallExpression expression = (CallExpression) context.syntaxNode(); - private void visitCallExpressionNode(CallExpression ce, SubscriptionContext ctx) { - for (Tree ele : ce.callee().children()) { - if (ele.getKind().equals(Tree.Kind.NAME)) { - Name name = (Name) ele; - if (name.name().equals("execute")) { - for (Argument a: ce.arguments()) { - if (checkLitteralInTree(a)) - ctx.addIssue(ce, MESSAGERULE); - } - } + if (expression.callee().is(Tree.Kind.QUALIFIED_EXPR)) { + String name = ((QualifiedExpression) expression.callee()).name().name(); + if (isUsingSqlLib && "execute".equals(name) && hasLoopParent(expression)) { + context.addIssue(expression, AvoidSQLRequestInLoop.MESSAGE_RULE); } } } - private boolean checkLitteralInTree(Tree t) { - for (Tree tc : t.children()) { - if (tc.is(Tree.Kind.STRING_LITERAL)) { - if (((StringLiteral) tc).trimmedQuotesValue().toUpperCase().contains("SELECT")) - return true; + private boolean hasLoopParent(Tree tree) { + for (Tree parent = tree.parent(); parent != null; parent = parent.parent()) { + Tree.Kind kind = parent.getKind(); + if (kind == Tree.Kind.FOR_STMT || kind == Tree.Kind.WHILE_STMT) { + return true; } - else if (checkLitteralInTree(tc)) - return true; } return false; } - -} +} \ No newline at end of file diff --git a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S72.html b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S72.html new file mode 100644 index 000000000..1d47ab791 --- /dev/null +++ b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S72.html @@ -0,0 +1,21 @@ +

Do not execute an SQL request in a loop

+

Noncompliant Code Example

+
+    def foo():
+        ...
+        results = []
+        for id in range(20):
+          results.append(cursor.execute("SELECT name FROM users where id = ?", (id)).fetchone()) # Noncompliant {{Avoid performing SQL queries within a loop}}
+        ...
+
+

Compliant Solution

+
+
+    def foo():
+        ...
+        ids = range(20)
+        results = cursor.execute("SELECT name FROM users where id IN ({0})".format(', '.join("?" * len(ids))), ids).fetchmany() # Compliant
+        ...
+   }
+
+
diff --git a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S72.json b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S72.json new file mode 100644 index 000000000..73743a5a5 --- /dev/null +++ b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S72.json @@ -0,0 +1,13 @@ +{ + "title": "Avoid SQL request in loop", + "type": "CODE_SMELL", + "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "10min" + }, + "tags": [ + "eco-conception" + ], + "defaultSeverity": "Minor" +} \ No newline at end of file diff --git a/src/python-plugin/src/test/java/fr/cnumr/python/CustomPythonRuleRepositoryTest.java b/src/python-plugin/src/test/java/fr/cnumr/python/CustomPythonRuleRepositoryTest.java index b9b20dbbc..391a2f335 100644 --- a/src/python-plugin/src/test/java/fr/cnumr/python/CustomPythonRuleRepositoryTest.java +++ b/src/python-plugin/src/test/java/fr/cnumr/python/CustomPythonRuleRepositoryTest.java @@ -33,7 +33,7 @@ public void test_rule_repository() { customPythonRuleRepository.define(context); assertThat(customPythonRuleRepository.repositoryKey()).isEqualTo(CustomPythonRuleRepository.REPOSITORY_KEY); assertThat(context.repositories()).hasSize(1).extracting("key").containsExactly(customPythonRuleRepository.repositoryKey()); - assertThat(context.repositories().get(0).rules()).hasSize(5); - assertThat(customPythonRuleRepository.checkClasses()).hasSize(5); + assertThat(context.repositories().get(0).rules()).hasSize(6); + assertThat(customPythonRuleRepository.checkClasses()).hasSize(6); } } diff --git a/src/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidSQLRequestInLoopCheckTest.java b/src/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidSQLRequestInLoopCheckTest.java deleted file mode 100644 index 42c43c427..000000000 --- a/src/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidSQLRequestInLoopCheckTest.java +++ /dev/null @@ -1,12 +0,0 @@ -package fr.cnumr.python.checks; - -import org.junit.Test; -import org.sonar.python.checks.utils.PythonCheckVerifier; - -public class AvoidSQLRequestInLoopCheckTest { - - @Test - public void test() { - PythonCheckVerifier.verify("src/test/resources/checks/avoidSQLRequestInLoopCheck.py", new AvoidSQLRequestInLoop()); - } -} diff --git a/src/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidSQLRequestInLoopTest.java b/src/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidSQLRequestInLoopTest.java new file mode 100644 index 000000000..811cae909 --- /dev/null +++ b/src/python-plugin/src/test/java/fr/cnumr/python/checks/AvoidSQLRequestInLoopTest.java @@ -0,0 +1,12 @@ +package fr.cnumr.python.checks; + +import org.junit.Test; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class AvoidSQLRequestInLoopTest { + @Test + public void test() { + PythonCheckVerifier.verify("src/test/resources/checks/avoidSQLRequestInLoop.py", new AvoidSQLRequestInLoop()); + PythonCheckVerifier.verifyNoIssue("src/test/resources/checks/avoidSQLRequestInLoopNoImports.py", new AvoidSQLRequestInLoop()); + } +} diff --git a/src/python-plugin/src/test/resources/checks/avoidSQLRequestInLoop.py b/src/python-plugin/src/test/resources/checks/avoidSQLRequestInLoop.py new file mode 100644 index 000000000..394088199 --- /dev/null +++ b/src/python-plugin/src/test/resources/checks/avoidSQLRequestInLoop.py @@ -0,0 +1,42 @@ +import mysql.connector +import psycopg2 +import pyodbc +import sqlite3 + +def mysql_loop(): + connection = mysql.connector.connect(database='local') + cursor = connection.cursor() + results = [] + for id in range(5): + results.append(cursor.execute("SELECT name FROM user WHERE id = ?", (id)).fetchone()) # Noncompliant {{Avoid performing SQL queries within a loop}} + connection.close() + return results + +def psycopg2_loop(): + connection = psycopg2.connect(database='local') + cursor = connection.cursor() + results = [] + id = 0 + while id <= 5: + results.append(cursor.execute("SELECT name FROM user WHERE id = ?", (id)).fetchone()) # Noncompliant {{Avoid performing SQL queries within a loop}} + id += 1 + connection.close() + return results + +def pyodbc_loop(): + connection = pyodbc.connect('DRIVER={ODBC Driver 17 for SQL Server};SERVER=localhost;DATABASE=local') + cursor = connection.cursor() + results = [] + for id in range(5): + results.append(cursor.execute("SELECT name FROM user WHERE id = ?", (id)).fetchone()) # Noncompliant {{Avoid performing SQL queries within a loop}} + connection.close() + return results + +def sqlite3_loop(): + connection = sqlite3.connect("local.db") + cursor = connection.cursor() + results = [] + for id in range(5): + results.append(cursor.execute("SELECT name FROM user WHERE id = ?", (id)).fetchone()) # Noncompliant {{Avoid performing SQL queries within a loop}} + connection.close() + return results diff --git a/src/python-plugin/src/test/resources/checks/avoidSQLRequestInLoopNoImports.py b/src/python-plugin/src/test/resources/checks/avoidSQLRequestInLoopNoImports.py new file mode 100644 index 000000000..fe8513844 --- /dev/null +++ b/src/python-plugin/src/test/resources/checks/avoidSQLRequestInLoopNoImports.py @@ -0,0 +1,26 @@ +def mysql_loop(): + connection = mysql.connector.connect(database='local') + cursor = connection.cursor() + results = [] + for id in range(5): + results.append(cursor.execute("SELECT name FROM user WHERE id = ?", (id)).fetchone()) # OK + connection.close() + return results + +def pyodbc_loop(): + connection = pyodbc.connect('DRIVER={ODBC Driver 17 for SQL Server};SERVER=localhost;DATABASE=local') + cursor = connection.cursor() + results = [] + for id in range(5): + results.append(cursor.execute("SELECT name FROM user WHERE id = ?", (id)).fetchone()) # OK + connection.close() + return results + +def sqlite3_loop(): + connection = sqlite3.connect("local.db") + cursor = connection.cursor() + results = [] + for id in range(5): + results.append(cursor.execute("SELECT name FROM user WHERE id = ?", (id)).fetchone()) # OK + connection.close() + return results From c3f048e982b9097bee22c3adc0d80b2713c29d19 Mon Sep 17 00:00:00 2001 From: Mohamed SALHAOUI <50855585+med-S@users.noreply.github.com> Date: Wed, 26 Oct 2022 08:29:25 +0100 Subject: [PATCH 061/119] Update MyJavaFileCheckRegistrarTest.java Fixed Build Issue --- .../test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java b/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java index 0bc3bcd6b..071e0bb4c 100644 --- a/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java +++ b/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java @@ -33,7 +33,7 @@ void checkNumberRules() { MyJavaFileCheckRegistrar registrar = new MyJavaFileCheckRegistrar(); registrar.register(context); - assertThat(context.checkClasses()).hasSize(9); + assertThat(context.checkClasses()).hasSize(10); assertThat(context.testCheckClasses()).isEmpty(); } From c399690d6989b2974543266c24905c07bbc9fe1f Mon Sep 17 00:00:00 2001 From: Mohamed SALHAOUI <50855585+med-S@users.noreply.github.com> Date: Wed, 26 Oct 2022 08:38:22 +0100 Subject: [PATCH 062/119] Update AvoidStatementForDMLQueries.java --- .../java/fr/cnumr/java/checks/AvoidStatementForDMLQueries.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidStatementForDMLQueries.java b/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidStatementForDMLQueries.java index 951f4e8dc..520372964 100644 --- a/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidStatementForDMLQueries.java +++ b/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidStatementForDMLQueries.java @@ -36,7 +36,7 @@ public void visitNode(Tree tree) { { LiteralTree literalTree = (LiteralTree) first; String str = literalTree.value(); - String regex = "(SELECT|INSERT INTO|UPDATE|DELETE FROM)\\s(.+,?)+\\s(FROM|VALUES|SET|WHERE)\\s?.*"; + String regex = "(SELECT|INSERT INTO|UPDATE|DELETE FROM)\\s?.*"; Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE); Matcher matcher = pattern.matcher(str); if (matcher.find()) From a518404dd08224c90883fe8be188645acca5a7ee Mon Sep 17 00:00:00 2001 From: Mohamed SALHAOUI <50855585+med-S@users.noreply.github.com> Date: Wed, 26 Oct 2022 09:10:29 +0100 Subject: [PATCH 063/119] Update RulesList.java Fixe conflit and compilation error --- src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java b/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java index ca1363e08..daff7780a 100644 --- a/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java +++ b/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java @@ -49,7 +49,7 @@ public static List> getJavaChecks() { AvoidFullSQLRequest.class, UseCorrectForLoop.class, UnnecessarilyAssignValuesToVariables.class, - InitializeBufferWithAppropriateSize.class + InitializeBufferWithAppropriateSize.class, AvoidUsingGlobalVariablesCheck.class, AvoidSetConstantInBatchUpdate.class )); From d5a022e265b8df7c6567f4b4ef7313a026cdf39e Mon Sep 17 00:00:00 2001 From: Antoine PRONNIER <44138938+FunixG@users.noreply.github.com> Date: Wed, 26 Oct 2022 10:47:01 +0200 Subject: [PATCH 064/119] [Rule-S77] Java Rule: Regex and Patterns usage (#156) * [Rule-S77] New java rule about Regex and Patterns * [Rule-S77] Fix test Co-authored-by: oussamaLaribi <63214114+oussamaLaribi@users.noreply.github.com> --- .../main/java/fr/cnumr/java/RulesList.java | 1 + .../checks/AvoidRegexPatternNotStatic.java | 63 ++++++++++++++++++ .../fr/cnumr/l10n/java/rules/java/S77.html | 66 +++++++++++++++++++ .../fr/cnumr/l10n/java/rules/java/S77.json | 13 ++++ .../files/AvoidRegexPatternNotStatic.java | 11 ++++ .../src/test/files/ValidRegexPattern.java | 12 ++++ .../src/test/files/ValidRegexPattern2.java | 12 ++++ .../src/test/files/ValidRegexPattern3.java | 16 +++++ .../java/MyJavaFileCheckRegistrarTest.java | 2 +- .../AvoidRegexPatternNotStaticTest.java | 27 ++++++++ 10 files changed, 222 insertions(+), 1 deletion(-) create mode 100644 src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidRegexPatternNotStatic.java create mode 100644 src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S77.html create mode 100644 src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S77.json create mode 100644 src/java-plugin/src/test/files/AvoidRegexPatternNotStatic.java create mode 100644 src/java-plugin/src/test/files/ValidRegexPattern.java create mode 100644 src/java-plugin/src/test/files/ValidRegexPattern2.java create mode 100644 src/java-plugin/src/test/files/ValidRegexPattern3.java create mode 100644 src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidRegexPatternNotStaticTest.java diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java b/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java index daff7780a..84fae7b2c 100644 --- a/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java +++ b/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java @@ -42,6 +42,7 @@ public static List> getChecks() { public static List> getJavaChecks() { return Collections.unmodifiableList(Arrays.asList( IncrementCheck.class, + AvoidRegexPatternNotStatic.class, NoFunctionCallWhenDeclaringForLoop.class, AvoidStatementForDMLQueries.class, AvoidSpringRepositoryCallInLoopCheck.class, diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidRegexPatternNotStatic.java b/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidRegexPatternNotStatic.java new file mode 100644 index 000000000..4201d6cda --- /dev/null +++ b/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidRegexPatternNotStatic.java @@ -0,0 +1,63 @@ +package fr.cnumr.java.checks; + +import org.sonar.check.Priority; +import org.sonar.check.Rule; +import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; +import org.sonar.plugins.java.api.semantic.MethodMatchers; +import org.sonar.plugins.java.api.tree.BaseTreeVisitor; +import org.sonar.plugins.java.api.tree.MethodInvocationTree; +import org.sonar.plugins.java.api.tree.MethodTree; +import org.sonar.plugins.java.api.tree.Tree; + +import javax.annotation.Nonnull; +import java.util.Collections; +import java.util.List; +import java.util.regex.Pattern; + +@Rule( + key = "S77", + name = "Developpement", + description = AvoidRegexPatternNotStatic.MESSAGE_RULE, + priority = Priority.MINOR, + tags = {"bug"}) +public class AvoidRegexPatternNotStatic extends IssuableSubscriptionVisitor { + + public static final String MESSAGE_RULE = "Avoid using Pattern.compile() in a non-static context."; + + private static final MethodMatchers PATTERN_COMPILE = MethodMatchers.create() + .ofTypes(Pattern.class.getName()) + .names("compile") + .withAnyParameters() + .build(); + + private final AvoidRegexPatternNotStaticVisitor visitor = new AvoidRegexPatternNotStaticVisitor(); + + @Override + public List nodesToVisit() { + return Collections.singletonList(Tree.Kind.METHOD); + } + + @Override + public void visitNode(@Nonnull Tree tree) { + if (tree instanceof MethodTree) { + final MethodTree methodTree = (MethodTree) tree; + + if (!methodTree.is(Tree.Kind.CONSTRUCTOR)) { + methodTree.accept(visitor); + } + } + } + + private class AvoidRegexPatternNotStaticVisitor extends BaseTreeVisitor { + + @Override + public void visitMethodInvocation(@Nonnull MethodInvocationTree tree) { + if (PATTERN_COMPILE.matches(tree)) { + reportIssue(tree, MESSAGE_RULE); + } else { + super.visitMethodInvocation(tree); + } + } + + } +} diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S77.html b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S77.html new file mode 100644 index 000000000..f5b98e93a --- /dev/null +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S77.html @@ -0,0 +1,66 @@ +

+ Avoid using Pattern.compile() in a non-static context. +

+ +

Noncompliant Code Example

+
+
+    public class AvoidRegexPatternNotStatic {
+
+        public boolean foo() {
+            final Pattern pattern = Pattern.compile("foo"); // Noncompliant
+            return pattern.matcher("foo").find();
+        }
+
+    }
+
+
+ +

Compliant Solution N°1

+
+
+    public class ValidRegexPattern {
+
+        private static final Pattern pattern = Pattern.compile("foo"); // Compliant
+
+        public boolean foo() {
+            return pattern.matcher("foo").find();
+        }
+
+    }
+
+
+ +

Compliant Solution N°2

+
+
+    public class ValidRegexPattern2 {
+
+        private final Pattern pattern = Pattern.compile("foo"); // Compliant
+
+        public boolean foo() {
+            return pattern.matcher("foo").find();
+        }
+
+    }
+
+
+ +

Compliant Solution N°3

+
+
+    public class ValidRegexPattern3 {
+
+        private final Pattern pattern;
+
+        public ValidRegexPattern3() {
+            pattern = Pattern.compile("foo"); // Compliant
+        }
+
+        public boolean foo() {
+            return pattern.matcher("foo").find();
+        }
+
+    }
+
+
diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S77.json b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S77.json new file mode 100644 index 000000000..a3bfcf120 --- /dev/null +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S77.json @@ -0,0 +1,13 @@ +{ + "title": "Avoid using Pattern.compile() in a non-static context.", + "type": "CODE_SMELL", + "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "20min" + }, + "tags": [ + "eco-conception" + ], + "defaultSeverity": "Minor" +} diff --git a/src/java-plugin/src/test/files/AvoidRegexPatternNotStatic.java b/src/java-plugin/src/test/files/AvoidRegexPatternNotStatic.java new file mode 100644 index 000000000..be39ca75a --- /dev/null +++ b/src/java-plugin/src/test/files/AvoidRegexPatternNotStatic.java @@ -0,0 +1,11 @@ +package fr.cnumr.java.checks; + +import java.util.regex.Pattern; + +public class AvoidRegexPatternNotStatic { + + public boolean foo() { + final Pattern pattern = Pattern.compile("foo"); // Noncompliant + return pattern.matcher("foo").find(); + } +} diff --git a/src/java-plugin/src/test/files/ValidRegexPattern.java b/src/java-plugin/src/test/files/ValidRegexPattern.java new file mode 100644 index 000000000..958c18eea --- /dev/null +++ b/src/java-plugin/src/test/files/ValidRegexPattern.java @@ -0,0 +1,12 @@ +package fr.cnumr.java.checks; + +import java.util.regex.Pattern; + +public class ValidRegexPattern { + + private static final Pattern pattern = Pattern.compile("foo"); // Compliant + + public boolean foo() { + return pattern.matcher("foo").find(); + } +} diff --git a/src/java-plugin/src/test/files/ValidRegexPattern2.java b/src/java-plugin/src/test/files/ValidRegexPattern2.java new file mode 100644 index 000000000..56b624fbd --- /dev/null +++ b/src/java-plugin/src/test/files/ValidRegexPattern2.java @@ -0,0 +1,12 @@ +package fr.cnumr.java.checks; + +import java.util.regex.Pattern; + +public class ValidRegexPattern2 { + + private final Pattern pattern = Pattern.compile("foo"); // Compliant + + public boolean foo() { + return pattern.matcher("foo").find(); + } +} diff --git a/src/java-plugin/src/test/files/ValidRegexPattern3.java b/src/java-plugin/src/test/files/ValidRegexPattern3.java new file mode 100644 index 000000000..6c1388abb --- /dev/null +++ b/src/java-plugin/src/test/files/ValidRegexPattern3.java @@ -0,0 +1,16 @@ +package fr.cnumr.java.checks; + +import java.util.regex.Pattern; + +public class ValidRegexPattern3 { + + private final Pattern pattern; + + public ValidRegexPattern3() { + pattern = Pattern.compile("foo"); // Compliant + } + + public boolean foo() { + return pattern.matcher("foo").find(); + } +} diff --git a/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java b/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java index 765a38986..0b0654e33 100644 --- a/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java +++ b/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java @@ -33,8 +33,8 @@ void checkNumberRules() { MyJavaFileCheckRegistrar registrar = new MyJavaFileCheckRegistrar(); registrar.register(context); - assertThat(context.checkClasses()).hasSize(11); + assertThat(context.checkClasses()).hasSize(12); assertThat(context.testCheckClasses()).isEmpty(); } diff --git a/src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidRegexPatternNotStaticTest.java b/src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidRegexPatternNotStaticTest.java new file mode 100644 index 000000000..710b3dea9 --- /dev/null +++ b/src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidRegexPatternNotStaticTest.java @@ -0,0 +1,27 @@ +package fr.cnumr.java.checks; + +import org.junit.jupiter.api.Test; +import org.sonar.java.checks.verifier.JavaCheckVerifier; + +public class AvoidRegexPatternNotStaticTest { + + @Test + public void testHasIssues() { + JavaCheckVerifier.newVerifier() + .onFile("src/test/files/AvoidRegexPatternNotStatic.java") + .withCheck(new AvoidRegexPatternNotStatic()) + .verifyIssues(); + } + + @Test + public void testHasNoIssues() { + JavaCheckVerifier.newVerifier() + .onFiles( + "src/test/files/ValidRegexPattern.java", + "src/test/files/ValidRegexPattern2.java", + "src/test/files/ValidRegexPattern3.java" + ) + .withCheck(new AvoidRegexPatternNotStatic()) + .verifyNoIssues(); + } +} From c74303f7756feb1dae75fda979abf24078aed692 Mon Sep 17 00:00:00 2001 From: Mohamed SALHAOUI <50855585+med-S@users.noreply.github.com> Date: Wed, 26 Oct 2022 10:57:28 +0100 Subject: [PATCH 065/119] Update build.yml Fix build error in sonarqube workflow --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b5a240ac0..87b5fd7e7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -40,4 +40,4 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - run: mvn -e -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=cnumr_ecoCode -Dsonar.organization=cnumr_1 -Dsonar.exclusions=**/src/codenarc-converter/**,**/*.groovy,**/src/android-plugin/src/test/**,**/*.dummy + run: mvn -e -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=cnumr_ecoCode -Dsonar.exclusions=**/src/codenarc-converter/**,**/*.groovy,**/src/android-plugin/src/test/**,**/*.dummy From 2269271cbe4bcf6a21055d5f47e187110b5f2585 Mon Sep 17 00:00:00 2001 From: Mohamed SALHAOUI <50855585+med-S@users.noreply.github.com> Date: Wed, 26 Oct 2022 11:08:03 +0100 Subject: [PATCH 066/119] Update AvoidGettingSizeCollectionInLoop.java Remove unused imports --- .../fr/cnumr/java/checks/AvoidGettingSizeCollectionInLoop.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidGettingSizeCollectionInLoop.java b/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidGettingSizeCollectionInLoop.java index 324e7fe8c..7571eff3f 100644 --- a/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidGettingSizeCollectionInLoop.java +++ b/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidGettingSizeCollectionInLoop.java @@ -1,7 +1,6 @@ package fr.cnumr.java.checks; import java.util.Arrays; -import java.util.Collection; import java.util.List; import org.sonar.check.Priority; @@ -11,8 +10,6 @@ import org.sonar.plugins.java.api.tree.*; import org.sonar.plugins.java.api.tree.Tree.Kind; -import static org.sonar.plugins.java.api.semantic.MethodMatchers.CONSTRUCTOR; - @Rule(key = "GSCIL", name = "Developpement", description = AvoidGettingSizeCollectionInLoop.MESSAGERULE, From f433f9d4e414af5902da2c847a4284360296264a Mon Sep 17 00:00:00 2001 From: Mohamed SALHAOUI <50855585+med-S@users.noreply.github.com> Date: Wed, 26 Oct 2022 11:14:22 +0100 Subject: [PATCH 067/119] Update AvoidGettingSizeCollectionInLoopTest.java Fixed Code Smell --- .../java/checks/AvoidGettingSizeCollectionInLoopTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidGettingSizeCollectionInLoopTest.java b/src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidGettingSizeCollectionInLoopTest.java index d4222ed2a..07b4c8454 100644 --- a/src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidGettingSizeCollectionInLoopTest.java +++ b/src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidGettingSizeCollectionInLoopTest.java @@ -3,7 +3,7 @@ import org.junit.jupiter.api.Test; import org.sonar.java.checks.verifier.JavaCheckVerifier; -public class AvoidGettingSizeCollectionInLoopTest { +class AvoidGettingSizeCollectionInLoopTest { @Test void test() { JavaCheckVerifier.newVerifier() @@ -15,4 +15,4 @@ void test() { .withCheck(new AvoidGettingSizeCollectionInLoop()) .verifyNoIssues(); } -} \ No newline at end of file +} From cafdcdb063e6a58cbe9ae7bde65ee69fce4ae392 Mon Sep 17 00:00:00 2001 From: Mohamed SALHAOUI <50855585+med-S@users.noreply.github.com> Date: Wed, 26 Oct 2022 15:14:53 +0100 Subject: [PATCH 068/119] Update OptimizeReadFileException.java Fixe SonarCloud Code Smell --- .../java/fr/cnumr/java/checks/OptimizeReadFileException.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/checks/OptimizeReadFileException.java b/src/java-plugin/src/main/java/fr/cnumr/java/checks/OptimizeReadFileException.java index 3e0f6fb08..0d1ba7d5f 100644 --- a/src/java-plugin/src/main/java/fr/cnumr/java/checks/OptimizeReadFileException.java +++ b/src/java-plugin/src/main/java/fr/cnumr/java/checks/OptimizeReadFileException.java @@ -3,7 +3,6 @@ import org.sonar.check.Priority; import org.sonar.check.Rule; -import org.sonar.java.model.statement.CatchTreeImpl; import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; import org.sonar.plugins.java.api.tree.CatchTree; import org.sonar.plugins.java.api.tree.NewClassTree; @@ -20,7 +19,7 @@ description = OptimizeReadFileException.MESSAGERULE, priority = Priority.MINOR, tags = {"bug"}) -public class OptimizeReadFileException extends IssuableSubscriptionVisitor { +public class OptimizeReadFileExceptions extends IssuableSubscriptionVisitor { protected static final String MESSAGERULE = "Optimize Read File Exception"; private boolean isFileNotFoundException = false; @@ -45,4 +44,4 @@ public void visitNode(Tree tree) { } return; } -} \ No newline at end of file +} From 401618581eb410032a16ce7e4e7f0f9c4126a685 Mon Sep 17 00:00:00 2001 From: Mohamed SALHAOUI <50855585+med-S@users.noreply.github.com> Date: Wed, 26 Oct 2022 15:17:24 +0100 Subject: [PATCH 069/119] Rename OptimizeReadFileException.java to OptimizeReadFileExceptions.java --- ...mizeReadFileException.java => OptimizeReadFileExceptions.java} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/java-plugin/src/main/java/fr/cnumr/java/checks/{OptimizeReadFileException.java => OptimizeReadFileExceptions.java} (100%) diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/checks/OptimizeReadFileException.java b/src/java-plugin/src/main/java/fr/cnumr/java/checks/OptimizeReadFileExceptions.java similarity index 100% rename from src/java-plugin/src/main/java/fr/cnumr/java/checks/OptimizeReadFileException.java rename to src/java-plugin/src/main/java/fr/cnumr/java/checks/OptimizeReadFileExceptions.java From d8784c750458d29f0be6b91f4cf1669914e020a0 Mon Sep 17 00:00:00 2001 From: Mohamed SALHAOUI <50855585+med-S@users.noreply.github.com> Date: Wed, 26 Oct 2022 15:20:17 +0100 Subject: [PATCH 070/119] Update RulesList.java --- src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java b/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java index 1a44a67d6..0e7b521cd 100644 --- a/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java +++ b/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java @@ -51,7 +51,7 @@ public static List> getJavaChecks() { AvoidFullSQLRequest.class, UseCorrectForLoop.class, UnnecessarilyAssignValuesToVariables.class, - OptimizeReadFileException.class, + OptimizeReadFileExceptions.class, InitializeBufferWithAppropriateSize.class, AvoidUsingGlobalVariablesCheck.class, AvoidSetConstantInBatchUpdate.class From 01583e0fcc351ee858e29024a1d8cf69eb03dae6 Mon Sep 17 00:00:00 2001 From: Mohamed SALHAOUI <50855585+med-S@users.noreply.github.com> Date: Wed, 26 Oct 2022 15:21:44 +0100 Subject: [PATCH 071/119] Update OptimizeReadFileExceptions.java --- .../java/fr/cnumr/java/checks/OptimizeReadFileExceptions.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/checks/OptimizeReadFileExceptions.java b/src/java-plugin/src/main/java/fr/cnumr/java/checks/OptimizeReadFileExceptions.java index 0d1ba7d5f..d76c8dcc9 100644 --- a/src/java-plugin/src/main/java/fr/cnumr/java/checks/OptimizeReadFileExceptions.java +++ b/src/java-plugin/src/main/java/fr/cnumr/java/checks/OptimizeReadFileExceptions.java @@ -16,12 +16,12 @@ @Rule( key = "GRSP0028", name = "Developpement", - description = OptimizeReadFileException.MESSAGERULE, + description = OptimizeReadFileExceptions.MESSAGERULE, priority = Priority.MINOR, tags = {"bug"}) public class OptimizeReadFileExceptions extends IssuableSubscriptionVisitor { - protected static final String MESSAGERULE = "Optimize Read File Exception"; + protected static final String MESSAGERULE = "Optimize Read File Exceptions"; private boolean isFileNotFoundException = false; @Override From 3ce33960eeab96a3cbf6e3174a4b1a173c54d0b1 Mon Sep 17 00:00:00 2001 From: Mohamed SALHAOUI <50855585+med-S@users.noreply.github.com> Date: Wed, 26 Oct 2022 15:22:10 +0100 Subject: [PATCH 072/119] Update GRSP0028.json --- .../resources/fr/cnumr/l10n/java/rules/java/GRSP0028.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRSP0028.json b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRSP0028.json index f22f6b6c2..ff67d411c 100644 --- a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRSP0028.json +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRSP0028.json @@ -1,5 +1,5 @@ { - "title": "Optimize read file exception", + "title": "Optimize read file exceptions", "type": "CODE_SMELL", "status": "ready", "remediation": { @@ -10,4 +10,4 @@ "eco-conception" ], "defaultSeverity": "Minor" -} \ No newline at end of file +} From 5aafacd200a5e10eaaed09c361da1577148c1233 Mon Sep 17 00:00:00 2001 From: Mohamed SALHAOUI <50855585+med-S@users.noreply.github.com> Date: Wed, 26 Oct 2022 15:22:46 +0100 Subject: [PATCH 073/119] Update OptimizeReadFileExceptionCheckTest.java --- .../cnumr/java/checks/OptimizeReadFileExceptionCheckTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java-plugin/src/test/java/fr/cnumr/java/checks/OptimizeReadFileExceptionCheckTest.java b/src/java-plugin/src/test/java/fr/cnumr/java/checks/OptimizeReadFileExceptionCheckTest.java index 008e58b23..998c97035 100644 --- a/src/java-plugin/src/test/java/fr/cnumr/java/checks/OptimizeReadFileExceptionCheckTest.java +++ b/src/java-plugin/src/test/java/fr/cnumr/java/checks/OptimizeReadFileExceptionCheckTest.java @@ -9,8 +9,8 @@ class OptimizeReadFileExceptionCheckTest { void test() { JavaCheckVerifier.newVerifier() .onFile("src/test/files/OptimizeReadFileExceptionCheck.java") - .withCheck(new OptimizeReadFileException()) + .withCheck(new OptimizeReadFileExceptions()) .verifyIssues(); } -} \ No newline at end of file +} From 5f87a6d35a1c85bfa33d14a12b652d4488a04548 Mon Sep 17 00:00:00 2001 From: dedece35 Date: Wed, 26 Oct 2022 16:54:12 +0200 Subject: [PATCH 074/119] correction of markdown typo --- hackathon/starter-pack.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hackathon/starter-pack.md b/hackathon/starter-pack.md index 779647d7a..21e1e3794 100644 --- a/hackathon/starter-pack.md +++ b/hackathon/starter-pack.md @@ -31,8 +31,11 @@ https://olegoaer.perso.univ-pau.fr/android-energy-smells/ ### Prerequesites You will need to install Docker : https://docs.docker.com/get-docker/ + Docker-compose 3.9 : https://docs.docker.com/compose/install/ + Java >=8 for Sonarqube plugin Development : https://www.java.com/fr/download/manual.jsp + Maven 3 for Sonarqube plugin Development : https://maven.apache.org/download.cgi Additionnaly, install Git : https://git-scm.com/book/en/v2/Getting-Started-Installing-Git From 2f3ff53d2f0fbc3da8ed055491e44dea3e68d192 Mon Sep 17 00:00:00 2001 From: dedece35 Date: Wed, 26 Oct 2022 16:55:13 +0200 Subject: [PATCH 075/119] add shell scripts to make it easy for installation and use + upgrade documentation --- src/INSTALL.md | 27 ++++++++++++++++++++++----- src/build.sh | 3 +++ src/init_reinit.sh | 3 +++ src/start.sh | 3 +++ src/stop.sh | 3 +++ 5 files changed, 34 insertions(+), 5 deletions(-) create mode 100755 src/build.sh create mode 100755 src/init_reinit.sh create mode 100755 src/start.sh create mode 100755 src/stop.sh diff --git a/src/INSTALL.md b/src/INSTALL.md index db4a3ae13..0a09bb220 100644 --- a/src/INSTALL.md +++ b/src/INSTALL.md @@ -33,7 +33,7 @@ You will find more information about the plugins’ architecture in their folder - Mvn 3 -### Preliminary steps +### Preliminary steps (only Android) The Android plugin uses [CodeNarc](https://codenarc.org/) to scan the gradle files of Android projects. To have more information about CodeNarc: [CodeNarc](/codenarc-converter/CodeNarc/README.md). @@ -52,10 +52,12 @@ You can build the project code by running the following command in the `src` dir Maven will download the required dependencies. ```sh -mvn clean install +./build.sh + +# execute `mvn clean install` ``` -Each plugin is generated in its own `src//target` directory, but they are also copied to the `src/lib` directory. +Each plugin is generated in its own `/target` directory, but they are also copied to the `lib` directory. @@ -71,7 +73,9 @@ You must have built the plugins (see the steps above). Run the SonarQube + PostgreSQL stack: ```sh -docker-compose up --build -d +./init_reinit.sh + +# execute `docker-compose up --build -d` ``` Check if the containers are up: @@ -134,7 +138,20 @@ Install dependencies from the root directory: mvn clean install ``` -.jar files (one per plugin) will be moved in `src/lib` repository after build. +.jar files (one per plugin) will be moved in `lib` repository after build. + +## Howto start or stop service (already installed) + +Once you did the installation a first time (and then you did custom configuration like quality gates, quality profiles, ...), +if you only want to start (or stop properly) existing services : + +```sh +./start.sh +# execute `docker-compose start` + +./stop.sh +# execute `docker-compose stop` +``` ## Links diff --git a/src/build.sh b/src/build.sh new file mode 100755 index 000000000..3d3e0d89d --- /dev/null +++ b/src/build.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env sh + +mvn clean compile diff --git a/src/init_reinit.sh b/src/init_reinit.sh new file mode 100755 index 000000000..fbc860637 --- /dev/null +++ b/src/init_reinit.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env sh + +docker-compose up --build -d \ No newline at end of file diff --git a/src/start.sh b/src/start.sh new file mode 100755 index 000000000..4d6041949 --- /dev/null +++ b/src/start.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env sh + +docker-compose start \ No newline at end of file diff --git a/src/stop.sh b/src/stop.sh new file mode 100755 index 000000000..460c5aa22 --- /dev/null +++ b/src/stop.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env sh + +docker-compose stop \ No newline at end of file From f47d38f62924931c67ef9d52a76aa79ac608ddbd Mon Sep 17 00:00:00 2001 From: Mohamed SALHAOUI <50855585+med-S@users.noreply.github.com> Date: Wed, 26 Oct 2022 16:13:47 +0100 Subject: [PATCH 076/119] Update .gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 94ad6a98e..0b3aa33ec 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ buildNumber.properties # Eclipse m2e generated files # Eclipse Core .project +.idea # JDT-specific (Eclipse Java Development Tools) .classpath -**/.settings \ No newline at end of file +**/.settings From d903119f88051bf67af86fa9574a065abbcc7230 Mon Sep 17 00:00:00 2001 From: dedece35 Date: Wed, 26 Oct 2022 17:42:46 +0200 Subject: [PATCH 077/119] upgrade gitignore to ignore all '.*' files except '.gitignore' file --- src/.gitignore | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/.gitignore b/src/.gitignore index 97a5726b0..f7a6afc7f 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -1,8 +1,8 @@ +!.gitignore +.* node_modules yarn.lock target/ node/ -.idea -.DS_Store *.iml /lib/*.jar From 55bd806c3a796a97d51bbb1fdcefa552312d124b Mon Sep 17 00:00:00 2001 From: dedece35 Date: Wed, 26 Oct 2022 17:45:34 +0200 Subject: [PATCH 078/119] delete worcspace files - best practice : do not commit workscpace files --- .idea/workspace.xml | 55 --------------------------------------------- 1 file changed, 55 deletions(-) delete mode 100644 .idea/workspace.xml diff --git a/.idea/workspace.xml b/.idea/workspace.xml deleted file mode 100644 index 4770f957b..000000000 --- a/.idea/workspace.xml +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - 1654173028185 - - - - - - - \ No newline at end of file From 9229d72c40c634f5769829d42eab51ede306c5e5 Mon Sep 17 00:00:00 2001 From: oussamaLaribi <63214114+oussamaLaribi@users.noreply.github.com> Date: Fri, 28 Oct 2022 10:23:11 +0100 Subject: [PATCH 079/119] Adapt the description of the rules (#163) --- .../fr/cnumr/l10n/java/rules/java/GRC1.html | 2 +- .../cnumr/l10n/java/rules/java/GRSP0032.html | 2 +- .../fr/cnumr/l10n/java/rules/java/GSCIL.html | 2 +- .../fr/cnumr/l10n/java/rules/java/S53.html | 2 +- .../fr/cnumr/l10n/java/rules/java/S63.html | 2 +- .../fr/cnumr/l10n/java/rules/java/S69.html | 2 +- .../fr/cnumr/l10n/java/rules/java/S77.html | 1 + .../fr/cnumr/l10n/java/rules/java/S78.html | 2 +- .../fr/cnumr/l10n/java/rules/java/SDMLQ1.html | 3 +- .../fr/cnumr/l10n/php/rules/custom/D1.html | 30 +++++++++++++++++-- .../fr/cnumr/l10n/php/rules/custom/S69.html | 2 +- .../fr/cnumr/l10n/python/rules/python/D4.html | 2 +- .../fr/cnumr/l10n/python/rules/python/D7.html | 2 +- .../cnumr/l10n/python/rules/python/S69.html | 2 +- .../cnumr/l10n/python/rules/python/S72.html | 2 +- 15 files changed, 43 insertions(+), 15 deletions(-) diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRC1.html b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRC1.html index 4b7c6e79a..8660346b6 100644 --- a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRC1.html +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRC1.html @@ -1,4 +1,4 @@ -

Using Spring repository in loop induced unnecessary calculation by the cpu so unless energy consumption

+

Using Spring repository in loop induced unnecessary calculation by the cpu so unless energy consumption.

Noncompliant Code Example

 		private final List<Integer> ids = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRSP0032.html b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRSP0032.html
index f4ae02219..3fb0f4343 100644
--- a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRSP0032.html
+++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRSP0032.html
@@ -1,6 +1,6 @@
 

If you know in advance how many characters would be appended, initialize builder/buffer with the appropriate size. - They will thus never have to be resized. + They will thus never have to be resized, It saves CPU cycles so unless energy consumption.

Noncompliant Code Example

diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GSCIL.html b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GSCIL.html
index 701cbfbc6..c082701a7 100644
--- a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GSCIL.html
+++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GSCIL.html
@@ -1,4 +1,4 @@
-

While iterating through any collection get the size of the collection beforehand and never get it during iteration. The sample is provided below as an illustration which is to be avoided as follows.

+

While iterating through any collection get the size of the collection beforehand and never get it during iteration, It saves CPU cycles so unless energy consumption. The sample is provided below as an illustration which is to be avoided as follows.

Noncompliant Code Example

 		List<String> objList = getData();
diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S53.html b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S53.html
index 4fe5b539b..b1d548c92 100644
--- a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S53.html
+++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S53.html
@@ -1,4 +1,4 @@
-

Using List instead of Arrays with Foreach save CPU cycles calculations and RAM consumption

+

Using List instead of Arrays with Foreach save CPU cycles calculations and RAM consumption.

Noncompliant Code Example

 		private final Integer[] intArray = new Integer[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S63.html b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S63.html
index 4541614bc..10c9026c4 100644
--- a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S63.html
+++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S63.html
@@ -1,4 +1,4 @@
-

Do not unnecessarily assign values to variables. It increase unless RAM memory usage

+

Do not unnecessarily assign values to variables. It increase unless RAM memory usage.

Noncompliant Code Example

 String var1 = getValue();
diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S69.html b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S69.html
index 49a79fabc..5d8c46aa1 100644
--- a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S69.html
+++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S69.html
@@ -1,4 +1,4 @@
-

Do not call a function when declaring a for-type loop in order to avoid function calls each iterations. It saves CPU cycles

+

Do not call a function when declaring a for-type loop in order to avoid function calls each iterations. It saves CPU cycles.

Noncompliant Code Example

     public void foo() {
diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S77.html b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S77.html
index f5b98e93a..8de04cef2 100644
--- a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S77.html
+++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S77.html
@@ -1,5 +1,6 @@
 

Avoid using Pattern.compile() in a non-static context. + This operation requires a non negligible amount of computational power, Using a single match saves CPU cycles and RAM consumption.

Noncompliant Code Example

diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S78.html b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S78.html index f28ae5d91..0ae356ffe 100644 --- a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S78.html +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S78.html @@ -1,4 +1,4 @@ -

Don't set const parameter in batch update => Put its in query

+

Don't set const parameter in batch update => Put its in query. Creating this parameter and destroying it consumes CPU cycles and RAM unnecessarily.

Noncompliant Code Example

     public void foo() {
diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/SDMLQ1.html b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/SDMLQ1.html
index f4416989b..e46b2c398 100644
--- a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/SDMLQ1.html
+++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/SDMLQ1.html
@@ -1,4 +1,5 @@
-

Use PreparedStatement instead of Statement

+

Use PreparedStatement instead of Statement, that's because SQL will validate the query only once, whereas if you just use a statement it will validate the query each time. + This induced unnecessary calculation by the cpu so unless energy consumption.

Noncompliant Code Example

     public void select() {
diff --git a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/D1.html b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/D1.html
index edf22ff81..5444a6196 100644
--- a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/D1.html
+++ b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/D1.html
@@ -1,2 +1,28 @@
-

Avoid using try-catch-finally statement

-

When an exception is thrown, a variable (the exception itself) is created in the catch block and destroyed at the end of the block. Creating this variable and destroying it consumes CPU cycles and RAM unnecessarily. It is better to prefer a logical test as much as possible.

+

Inside complex code parts (for exemple multiple loops, complex data constructions...), avoid using try...catch...finally.

+

When an exception is thrown, a variable (the exception itself) is created in a catch block and it's destruction consumes unnecessary CPU cycles and RAM. Prefer using logical tests in this cases.

+

Noncompliant Code Example

+
+try
+{
+  $picture = PDF_open_image_file($PDF, "jpeg", $imgFile, "", 0); // This is the original statement, this works on PHP4
+}
+catch(Exception $ex)
+{
+  $msg = "Error opening $imgFile for Product $row['Identifier']";
+  throw new Exception($msg);
+}
+
+
+

Compliant Solution

+
+//try
+if (file_exists($imgFile)) {
+    $picture = PDF_open_image_file($PDF, "jpeg", $imgFile, "", 0);
+}
+
+//catch
+if (!$picture) {
+   $msg = "Error opening $imgFile for Product $row['Identifier']";
+   print $msg;
+}
+
diff --git a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S69.html b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S69.html index 5db857866..093abe723 100644 --- a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S69.html +++ b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/S69.html @@ -1,4 +1,4 @@ -

Do not call a function when declaring a for-type loop in order to avoid function calls each iterations. It saves CPU cycles

+

Do not call a function when declaring a for-type loop in order to avoid function calls each iterations. It saves CPU cycles.

Noncompliant Code Example

 for ($i = 0; $i <= foo(); $i++) { // NOK
diff --git a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/D4.html b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/D4.html
index 812ad2886..c92e7e5be 100644
--- a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/D4.html
+++ b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/D4.html
@@ -1,4 +1,4 @@
-

When function calls global variables, a lot a CPU cycles is consumed

+

When function calls global variables, a lot a CPU cycles is consumed.

Noncompliant Code Example

 global_var = 'foo'
diff --git a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/D7.html b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/D7.html
index ec24f940d..181906af2 100644
--- a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/D7.html
+++ b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/D7.html
@@ -1,4 +1,4 @@
-

Eviter de créer des méthodes getter et setter dans les classes.

+

Avoid Getters and Setters in class, It increase unless RAM memory usage.

Noncompliant Code Example

 class Client():
diff --git a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S69.html b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S69.html
index 088ad39de..4b90e50d4 100644
--- a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S69.html
+++ b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S69.html
@@ -1,4 +1,4 @@
-

raises an issue on a For statement. with a visitor on which you can control the visit.

+

Do not call a function when declaring a for-type loop in order to avoid function calls each iterations. It saves CPU cycles.

Noncompliant Code Example

 for i in my_function():
diff --git a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S72.html b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S72.html
index 1d47ab791..837f0493d 100644
--- a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S72.html
+++ b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/S72.html
@@ -1,4 +1,4 @@
-

Do not execute an SQL request in a loop

+

Executing SQL queries in loop induced unnecessary calculation by the cpu, RAM usage and network transfert.

Noncompliant Code Example

     def foo():

From e3812e737bd1b0ee184854055129311eac19191c Mon Sep 17 00:00:00 2001
From: Antoine PRONNIER <44138938+FunixG@users.noreply.github.com>
Date: Fri, 28 Oct 2022 12:08:37 +0200
Subject: [PATCH 080/119] [Rule-S76] Java Rule: Avoid static collection usage
 (#155)

* [Rule-S76] Init new rule about static collection usage

* [Rule-S76] WIP rule static

* [Rule-S76] WIP rule static

* [Rule-S76] Add non compliant to test files

Co-authored-by: oussamaLaribi <63214114+oussamaLaribi@users.noreply.github.com>
---
 .../main/java/fr/cnumr/java/RulesList.java    |  1 +
 .../checks/AvoidUsageOfStaticCollections.java | 55 +++++++++++++++++++
 .../fr/cnumr/l10n/java/rules/java/S76.html    | 38 +++++++++++++
 .../fr/cnumr/l10n/java/rules/java/S76.json    | 13 +++++
 .../files/AvoidUsageOfStaticCollections.java  | 19 +++++++
 .../files/GoodUsageOfStaticCollections.java   | 17 ++++++
 .../java/MyJavaFileCheckRegistrarTest.java    |  2 +-
 .../AvoidUsageOfStaticCollectionsTests.java   | 24 ++++++++
 8 files changed, 168 insertions(+), 1 deletion(-)
 create mode 100644 src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidUsageOfStaticCollections.java
 create mode 100644 src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S76.html
 create mode 100644 src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S76.json
 create mode 100644 src/java-plugin/src/test/files/AvoidUsageOfStaticCollections.java
 create mode 100644 src/java-plugin/src/test/files/GoodUsageOfStaticCollections.java
 create mode 100644 src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidUsageOfStaticCollectionsTests.java

diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java b/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java
index 0e7b521cd..561221545 100644
--- a/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java
+++ b/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java
@@ -42,6 +42,7 @@ public static List> getChecks() {
     public static List> getJavaChecks() {
         return Collections.unmodifiableList(Arrays.asList(
                 IncrementCheck.class,
+                AvoidUsageOfStaticCollections.class,
                 AvoidGettingSizeCollectionInLoop.class,
                 AvoidRegexPatternNotStatic.class,
                 NoFunctionCallWhenDeclaringForLoop.class,
diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidUsageOfStaticCollections.java b/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidUsageOfStaticCollections.java
new file mode 100644
index 000000000..638656b93
--- /dev/null
+++ b/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidUsageOfStaticCollections.java
@@ -0,0 +1,55 @@
+package fr.cnumr.java.checks;
+
+import org.sonar.check.Priority;
+import org.sonar.check.Rule;
+import org.sonar.plugins.java.api.IssuableSubscriptionVisitor;
+import org.sonar.plugins.java.api.tree.BaseTreeVisitor;
+import org.sonar.plugins.java.api.tree.Tree;
+import org.sonar.plugins.java.api.tree.VariableTree;
+
+import javax.annotation.Nonnull;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+@Rule(
+        key = "S76",
+        name = "Developpement",
+        description = AvoidUsageOfStaticCollections.MESSAGE_RULE,
+        priority = Priority.MINOR,
+        tags = {"bug"})
+public class AvoidUsageOfStaticCollections extends IssuableSubscriptionVisitor {
+
+    protected static final String MESSAGE_RULE = "Avoid usage of static collections.";
+
+    private final AvoidUsageOfStaticCollectionsVisitor visitor = new AvoidUsageOfStaticCollectionsVisitor();
+
+    @Override
+    public List nodesToVisit() {
+        return Collections.singletonList(
+                Tree.Kind.VARIABLE
+        );
+    }
+
+    @Override
+    public void visitNode(@Nonnull Tree tree) {
+        tree.accept(visitor);
+    }
+
+    private class AvoidUsageOfStaticCollectionsVisitor extends BaseTreeVisitor {
+
+        @Override
+        public void visitVariable(@Nonnull VariableTree tree) {
+            if (tree.symbol().isStatic() &&
+                    (tree.type().symbolType().isSubtypeOf(Iterable.class.getName()) ||
+                            tree.type().symbolType().is(Map.class.getName()))
+            ) {
+                reportIssue(tree, MESSAGE_RULE);
+            } else {
+                super.visitVariable(tree);
+            }
+        }
+
+    }
+
+}
diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S76.html b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S76.html
new file mode 100644
index 000000000..608b0285b
--- /dev/null
+++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S76.html
@@ -0,0 +1,38 @@
+

+ Avoid usage of static collections.
+ If you want to use static collections make them final and create for example a singleton if needed containing the collections.
+ The static fields are more complicated for the Garbage Collector to manage and can lead to memory leaks. +

+ +

Noncompliant Code Example

+
+
+    /**
+     * Not compliant
+     */
+    public class AvoidUsageOfStaticCollections {
+        public static final List<> LIST = new ArrayList<>();
+        public static final Set<> SET = new HashSet<>();
+        public static final Map<> MAP = new HashMap<>();
+    }
+
+
+ +

Compliant Solution

+
+
+    /**
+     * Compliant
+     */
+    public class GoodUsageOfStaticCollections {
+        public static volatile GoodUsageOfStaticCollections INSTANCE = new GoodUsageOfStaticCollections();
+
+        public final List<> LIST = new ArrayList<>();
+        public final Set<> SET = new HashSet<>();
+        public final Map<> MAP = new HashMap<>();
+
+        private GoodUsageOfStaticCollections() {
+        }
+    }
+
+
\ No newline at end of file diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S76.json b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S76.json new file mode 100644 index 000000000..e59d0fc9f --- /dev/null +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S76.json @@ -0,0 +1,13 @@ +{ + "title": "Avoid usage of static collections.", + "type": "CODE_SMELL", + "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "20min" + }, + "tags": [ + "eco-conception" + ], + "defaultSeverity": "Minor" +} \ No newline at end of file diff --git a/src/java-plugin/src/test/files/AvoidUsageOfStaticCollections.java b/src/java-plugin/src/test/files/AvoidUsageOfStaticCollections.java new file mode 100644 index 000000000..ec3736106 --- /dev/null +++ b/src/java-plugin/src/test/files/AvoidUsageOfStaticCollections.java @@ -0,0 +1,19 @@ +package fr.cnumr.java.checks; + +import java.util.*; + +/** + * Not compliant + */ +public class AvoidUsageOfStaticCollections { + + public static final List LIST = new ArrayList(); // Noncompliant + + public static final Set SET = new HashSet(); // Noncompliant + + public static final Map MAP = new HashMap(); // Noncompliant + + public AvoidUsageOfStaticCollections() { + } + +} diff --git a/src/java-plugin/src/test/files/GoodUsageOfStaticCollections.java b/src/java-plugin/src/test/files/GoodUsageOfStaticCollections.java new file mode 100644 index 000000000..bab0372e2 --- /dev/null +++ b/src/java-plugin/src/test/files/GoodUsageOfStaticCollections.java @@ -0,0 +1,17 @@ +package fr.cnumr.java.checks; + +import java.util.*; + +/** + * Compliant + */ +public class GoodUsageOfStaticCollections { + public static volatile GoodUsageOfStaticCollections INSTANCE = new GoodUsageOfStaticCollections(); + + public final List LIST = new ArrayList(); // Compliant + public final Set SET = new HashSet(); // Compliant + public final Map MAP = new HashMap(); // Compliant + + private GoodUsageOfStaticCollections() { + } +} diff --git a/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java b/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java index 570fc4578..aeb839f49 100644 --- a/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java +++ b/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java @@ -33,8 +33,8 @@ void checkNumberRules() { MyJavaFileCheckRegistrar registrar = new MyJavaFileCheckRegistrar(); registrar.register(context); - assertThat(context.checkClasses()).hasSize(14); + assertThat(context.checkClasses()).hasSize(15); assertThat(context.testCheckClasses()).isEmpty(); } diff --git a/src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidUsageOfStaticCollectionsTests.java b/src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidUsageOfStaticCollectionsTests.java new file mode 100644 index 000000000..74ddfc6b7 --- /dev/null +++ b/src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidUsageOfStaticCollectionsTests.java @@ -0,0 +1,24 @@ +package fr.cnumr.java.checks; + +import org.junit.jupiter.api.Test; +import org.sonar.java.checks.verifier.JavaCheckVerifier; + +public class AvoidUsageOfStaticCollectionsTests { + + @Test + public void testHasIssues() { + JavaCheckVerifier.newVerifier() + .onFile("src/test/files/AvoidUsageOfStaticCollections.java") + .withCheck(new AvoidUsageOfStaticCollections()) + .verifyIssues(); + } + + @Test + public void testNoIssues() { + JavaCheckVerifier.newVerifier() + .onFile("src/test/files/GoodUsageOfStaticCollections.java") + .withCheck(new AvoidUsageOfStaticCollections()) + .verifyNoIssues(); + } + +} From 910ec5ffc8a64b969ad78437b5529a2696663395 Mon Sep 17 00:00:00 2001 From: David Crescence Date: Thu, 2 Jun 2022 14:42:15 +0200 Subject: [PATCH 081/119] Adding all three files in draft. --- .../java/checks/sobriety/HighFrameRateRule.java | 17 +++++++++++++++++ .../test/files/sobriety/HighFrameRateCheck.java | 7 +++++++ .../checks/sobriety/HighFrameRateCheckTest.java | 14 ++++++++++++++ 3 files changed, 38 insertions(+) create mode 100644 src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java create mode 100644 src/android-plugin/src/test/files/sobriety/HighFrameRateCheck.java create mode 100644 src/android-plugin/src/test/java/io/ecocode/java/checks/sobriety/HighFrameRateCheckTest.java diff --git a/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java b/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java new file mode 100644 index 000000000..590fc0110 --- /dev/null +++ b/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java @@ -0,0 +1,17 @@ +package org.sonar.samples.java.checks; + +import org.sonar.check.Rule; +import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; +import org.sonar.plugins.java.api.tree.Tree.Kind; +import java.util.Collections; +import java.util.List; + +@Rule(key = "HighFrameRateRule") +class HighFrameRateCheck { + + @Override + public List nodesToVisit() { + return Collections.emptyList(); + } + +} \ No newline at end of file diff --git a/src/android-plugin/src/test/files/sobriety/HighFrameRateCheck.java b/src/android-plugin/src/test/files/sobriety/HighFrameRateCheck.java new file mode 100644 index 000000000..0c69247c7 --- /dev/null +++ b/src/android-plugin/src/test/files/sobriety/HighFrameRateCheck.java @@ -0,0 +1,7 @@ +class HighFrameRateCheck { + + public void test() { + + } + +} \ No newline at end of file diff --git a/src/android-plugin/src/test/java/io/ecocode/java/checks/sobriety/HighFrameRateCheckTest.java b/src/android-plugin/src/test/java/io/ecocode/java/checks/sobriety/HighFrameRateCheckTest.java new file mode 100644 index 000000000..20c914dc0 --- /dev/null +++ b/src/android-plugin/src/test/java/io/ecocode/java/checks/sobriety/HighFrameRateCheckTest.java @@ -0,0 +1,14 @@ +package org.sonar.samples.java.checks; + +import org.junit.jupiter.api.Test; + +class HighFrameRateCheckTest { + + @Test + public void verify() { + JavaCheckVerifier.newVerifier().onFile("src/test/files/sobriety/HighFrameRateRule.java") + .withChecks(new HighFrameRateRule()) + .verifyIssues(); + } + +} \ No newline at end of file From 097c2a9687a952190d3214b4f4e2da4befb10270 Mon Sep 17 00:00:00 2001 From: David Crescence Date: Thu, 2 Jun 2022 15:45:20 +0200 Subject: [PATCH 082/119] Adding specific method check super type to the rule. --- .../checks/sobriety/HighFrameRateRule.java | 20 +++++++++---------- .../files/sobriety/HighFrameRateCheck.java | 17 +++++++++++++++- .../sobriety/HighFrameRateCheckTest.java | 4 +++- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java b/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java index 590fc0110..8b7e9b167 100644 --- a/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java +++ b/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java @@ -1,17 +1,17 @@ -package org.sonar.samples.java.checks; +package io.ecocode.java.checks.sobriety; +import io.ecocode.java.checks.helpers.SpecificMethodCheck; import org.sonar.check.Rule; -import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; -import org.sonar.plugins.java.api.tree.Tree.Kind; -import java.util.Collections; -import java.util.List; -@Rule(key = "HighFrameRateRule") -class HighFrameRateCheck { +@Rule(key = "ESOB014", name= "ecoCodeHighFrameRate") +public class HighFrameRateRule extends SpecificMethodCheck { - @Override - public List nodesToVisit() { - return Collections.emptyList(); + public HighFrameRateRule() { + super("android.view.Surface","setFrameRate"); } + @Override + public String getMessage() { + return ""; + } } \ No newline at end of file diff --git a/src/android-plugin/src/test/files/sobriety/HighFrameRateCheck.java b/src/android-plugin/src/test/files/sobriety/HighFrameRateCheck.java index 0c69247c7..c3b1baf51 100644 --- a/src/android-plugin/src/test/files/sobriety/HighFrameRateCheck.java +++ b/src/android-plugin/src/test/files/sobriety/HighFrameRateCheck.java @@ -1,7 +1,22 @@ -class HighFrameRateCheck { +package android.view; + +class Surface { + + public static final int FRAME_RATE_COMPATIBILITY_DEFAULT = 0; + public static final int FRAME_RATE_COMPATIBILITY_FIXED_SOURCE = 1; + public static final int CHANGE_FRAME_RATE_ALWAYS = 1; + public static final int CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS = 0; public void test() { + Surface surface = new Surface(); + } + + public void setFrameRate(float frameRate, int compatibility) { + return; + } + public void setFrameRate(float frameRate, int compatibility, int changeFrameRateStrategy) { + return; } } \ No newline at end of file diff --git a/src/android-plugin/src/test/java/io/ecocode/java/checks/sobriety/HighFrameRateCheckTest.java b/src/android-plugin/src/test/java/io/ecocode/java/checks/sobriety/HighFrameRateCheckTest.java index 20c914dc0..61ac0bab2 100644 --- a/src/android-plugin/src/test/java/io/ecocode/java/checks/sobriety/HighFrameRateCheckTest.java +++ b/src/android-plugin/src/test/java/io/ecocode/java/checks/sobriety/HighFrameRateCheckTest.java @@ -1,6 +1,8 @@ package org.sonar.samples.java.checks; -import org.junit.jupiter.api.Test; +import io.ecocode.java.checks.sobriety.HighFrameRateRule; +import org.junit.Test; +import org.sonar.java.checks.verifier.JavaCheckVerifier; class HighFrameRateCheckTest { From 19488238134d7a6c89d0878559d97757b459d157 Mon Sep 17 00:00:00 2001 From: David Crescence Date: Thu, 2 Jun 2022 16:22:21 +0200 Subject: [PATCH 083/119] Adding test case to test file. --- .../java/checks/sobriety/HighFrameRateRule.java | 2 +- .../src/test/files/sobriety/HighFrameRateCheck.java | 10 ++++++---- .../java/checks/sobriety/HighFrameRateCheckTest.java | 7 +++---- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java b/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java index 8b7e9b167..5166da422 100644 --- a/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java +++ b/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java @@ -12,6 +12,6 @@ public HighFrameRateRule() { @Override public String getMessage() { - return ""; + return "Not overriding setFrameRate default behavior is recommanded to avoid higher battery usage."; } } \ No newline at end of file diff --git a/src/android-plugin/src/test/files/sobriety/HighFrameRateCheck.java b/src/android-plugin/src/test/files/sobriety/HighFrameRateCheck.java index c3b1baf51..05628a599 100644 --- a/src/android-plugin/src/test/files/sobriety/HighFrameRateCheck.java +++ b/src/android-plugin/src/test/files/sobriety/HighFrameRateCheck.java @@ -2,13 +2,15 @@ class Surface { - public static final int FRAME_RATE_COMPATIBILITY_DEFAULT = 0; - public static final int FRAME_RATE_COMPATIBILITY_FIXED_SOURCE = 1; - public static final int CHANGE_FRAME_RATE_ALWAYS = 1; - public static final int CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS = 0; + private static final int FRAME_RATE_COMPATIBILITY_DEFAULT = 0; + private static final int FRAME_RATE_COMPATIBILITY_FIXED_SOURCE = 1; + private static final int CHANGE_FRAME_RATE_ALWAYS = 1; + private static final int CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS = 0; public void test() { Surface surface = new Surface(); + surface.setFrameRate(120.0f,0); // Noncompliant +// surface.setFrameRate(90.0f,FRAME_RATE_COMPATIBILITY_FIXED_SOURCE); } public void setFrameRate(float frameRate, int compatibility) { diff --git a/src/android-plugin/src/test/java/io/ecocode/java/checks/sobriety/HighFrameRateCheckTest.java b/src/android-plugin/src/test/java/io/ecocode/java/checks/sobriety/HighFrameRateCheckTest.java index 61ac0bab2..162a11564 100644 --- a/src/android-plugin/src/test/java/io/ecocode/java/checks/sobriety/HighFrameRateCheckTest.java +++ b/src/android-plugin/src/test/java/io/ecocode/java/checks/sobriety/HighFrameRateCheckTest.java @@ -1,14 +1,13 @@ -package org.sonar.samples.java.checks; +package io.ecocode.java.checks.sobriety; -import io.ecocode.java.checks.sobriety.HighFrameRateRule; import org.junit.Test; import org.sonar.java.checks.verifier.JavaCheckVerifier; -class HighFrameRateCheckTest { +public class HighFrameRateCheckTest { @Test public void verify() { - JavaCheckVerifier.newVerifier().onFile("src/test/files/sobriety/HighFrameRateRule.java") + JavaCheckVerifier.newVerifier().onFile("src/test/files/sobriety/HighFrameRateCheck.java") .withChecks(new HighFrameRateRule()) .verifyIssues(); } From 4809574e3c376559362301d931f84858e245509f Mon Sep 17 00:00:00 2001 From: David Crescence Date: Thu, 2 Jun 2022 17:46:38 +0200 Subject: [PATCH 084/119] Updating test file with according sonar message rule test. --- .../src/test/files/sobriety/HighFrameRateCheck.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/android-plugin/src/test/files/sobriety/HighFrameRateCheck.java b/src/android-plugin/src/test/files/sobriety/HighFrameRateCheck.java index 05628a599..4fe1b1f92 100644 --- a/src/android-plugin/src/test/files/sobriety/HighFrameRateCheck.java +++ b/src/android-plugin/src/test/files/sobriety/HighFrameRateCheck.java @@ -7,10 +7,9 @@ class Surface { private static final int CHANGE_FRAME_RATE_ALWAYS = 1; private static final int CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS = 0; - public void test() { + public void test() { Surface surface = new Surface(); - surface.setFrameRate(120.0f,0); // Noncompliant -// surface.setFrameRate(90.0f,FRAME_RATE_COMPATIBILITY_FIXED_SOURCE); + surface.setFrameRate(0.0f,0); // Noncompliant {{Not overriding setFrameRate default behavior is recommanded to avoid higher battery usage.}} } public void setFrameRate(float frameRate, int compatibility) { From a368fabbf7cb186709253fcc61b5eeec768b9c91 Mon Sep 17 00:00:00 2001 From: PJCR0451 Date: Thu, 2 Jun 2022 18:05:36 +0200 Subject: [PATCH 085/119] add html and json files --- .../l10n/java/rules/squid/ESOB014_java.html | 18 ++++++++++++++++++ .../l10n/java/rules/squid/ESOB014_java.json | 15 +++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 src/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ESOB014_java.html create mode 100644 src/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ESOB014_java.json diff --git a/src/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ESOB014_java.html b/src/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ESOB014_java.html new file mode 100644 index 000000000..16847c7f0 --- /dev/null +++ b/src/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ESOB014_java.html @@ -0,0 +1,18 @@ + +

In Android 11 (API level 30) or higher, a call to + Surface#setFrameRate(float frameRate, int compatibility) results in a change to the display refresh + rate. However, a regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence + saving energy, this frequency should not be raised to 90Hz or 120Hz, despite this is now supported by many devices. +

+

Noncompliant Code Example

+
+    surface.setFrameRate(120f, FRAME_RATE_COMPATIBILITY_DEFAULT);
+
+

Compliant Code Example

+
+    surface.setFrameRate(60f, FRAME_RATE_COMPATIBILITY_DEFAULT);
+
+OR +
+    surface.setFrameRate(0f, FRAME_RATE_COMPATIBILITY_DEFAULT);
+
\ No newline at end of file diff --git a/src/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ESOB014_java.json b/src/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ESOB014_java.json new file mode 100644 index 000000000..4cad3847f --- /dev/null +++ b/src/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ESOB014_java.json @@ -0,0 +1,15 @@ +{ + "title": "Sobriety: High Frame Rate", + "type": "CODE_SMELL", + "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "5min" + }, + "tags": [ + "sobriety", + "environment", + "ecocode" + ], + "defaultSeverity": "Major" +} \ No newline at end of file From 464de201dc6d333c941711622d14925db0d53595 Mon Sep 17 00:00:00 2001 From: PJCR0451 Date: Thu, 2 Jun 2022 18:18:56 +0200 Subject: [PATCH 086/119] add rule to java profile --- .../src/main/java/io/ecocode/java/JavaCheckList.java | 3 ++- .../l10n/java/rules/squid/ecocode_java_profile.json | 12 +----------- .../io/ecocode/java/JavaRulesDefinitionTest.java | 6 ++++++ 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/android-plugin/src/main/java/io/ecocode/java/JavaCheckList.java b/src/android-plugin/src/main/java/io/ecocode/java/JavaCheckList.java index 774710505..74f8fea7a 100644 --- a/src/android-plugin/src/main/java/io/ecocode/java/JavaCheckList.java +++ b/src/android-plugin/src/main/java/io/ecocode/java/JavaCheckList.java @@ -82,7 +82,8 @@ public static List> getJavaChecks() { SensorCoalesceRule.class, JobCoalesceRule.class, SaveModeAwarenessRule.class, - ThriftyGeolocationCriteriaRule.class + ThriftyGeolocationCriteriaRule.class, + HighFrameRateRule.class )); } diff --git a/src/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ecocode_java_profile.json b/src/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ecocode_java_profile.json index 5dccc9efd..eaffad9a8 100644 --- a/src/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ecocode_java_profile.json +++ b/src/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ecocode_java_profile.json @@ -32,16 +32,6 @@ "ESOB011", "ESOB012", "ESOB013", - "EOPT001", - "EOPT002", - "EIDL001", - "EIDL002", - "EIDL004", - "EIDL006", - "EIDL007", - "EIDL008", - "EIDL009", - "EPOW004", - "ESOB012" + "ESOB014" ] } \ No newline at end of file diff --git a/src/android-plugin/src/test/java/io/ecocode/java/JavaRulesDefinitionTest.java b/src/android-plugin/src/test/java/io/ecocode/java/JavaRulesDefinitionTest.java index 8f78edbca..c2fd381c3 100644 --- a/src/android-plugin/src/test/java/io/ecocode/java/JavaRulesDefinitionTest.java +++ b/src/android-plugin/src/test/java/io/ecocode/java/JavaRulesDefinitionTest.java @@ -233,6 +233,12 @@ private void assertRuleProperties(Repository repository) { assertThat(torchFree.name()).isEqualTo("Sobriety: Torch Free"); assertThat(torchFree.debtRemediationFunction().type()).isEqualTo(Type.CONSTANT_ISSUE); assertThat(torchFree.type()).isEqualTo(RuleType.CODE_SMELL); + + Rule highFrameRate = repository.rule("ESOB014"); + assertThat(highFrameRate).isNotNull(); + assertThat(highFrameRate.name()).isEqualTo("Sobriety: High Frame Rate"); + assertThat(highFrameRate.debtRemediationFunction().type()).isEqualTo(Type.CONSTANT_ISSUE); + assertThat(highFrameRate.type()).isEqualTo(RuleType.CODE_SMELL); } private void assertAllRuleParametersHaveDescription(Repository repository) { From 505608773f9b0d21988084b75e4e438dfdb02676 Mon Sep 17 00:00:00 2001 From: David Crescence Date: Thu, 2 Jun 2022 18:48:26 +0200 Subject: [PATCH 087/119] Adding the argument matcher for fps greater than 60. --- .../checks/sobriety/HighFrameRateRule.java | 39 +++++++++++++++++-- .../files/sobriety/HighFrameRateCheck.java | 5 ++- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java b/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java index 5166da422..e7ce0f3bf 100644 --- a/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java +++ b/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java @@ -1,17 +1,48 @@ package io.ecocode.java.checks.sobriety; +import com.google.common.collect.ImmutableList; +import io.ecocode.java.checks.helpers.CheckArgumentComplexType; import io.ecocode.java.checks.helpers.SpecificMethodCheck; import org.sonar.check.Rule; +import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; +import org.sonar.plugins.java.api.semantic.MethodMatchers; +import org.sonar.plugins.java.api.tree.*; + +import java.util.List; @Rule(key = "ESOB014", name= "ecoCodeHighFrameRate") -public class HighFrameRateRule extends SpecificMethodCheck { +public class HighFrameRateRule extends IssuableSubscriptionVisitor { + + private final MethodMatchers surfaceListenerMethodMatcher = MethodMatchers.create().ofTypes("android.view.Surface").names("setFrameRate").withAnyParameters().build(); public HighFrameRateRule() { - super("android.view.Surface","setFrameRate"); + super(); } @Override - public String getMessage() { - return "Not overriding setFrameRate default behavior is recommanded to avoid higher battery usage."; + public List nodesToVisit() { + return ImmutableList.of(Tree.Kind.METHOD_INVOCATION); + } + + @Override + public void visitNode(Tree tree) { + if (tree.is(Tree.Kind.METHOD_INVOCATION)) { + MethodInvocationTree methodInvocationTree = (MethodInvocationTree) tree; + if (surfaceListenerMethodMatcher.matches(methodInvocationTree)) { + if (!isRefreshSixtyOrLower(methodInvocationTree.arguments())) { + reportIssue(methodInvocationTree, "A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz."); + } + } + } + } + + private boolean isRefreshSixtyOrLower(Arguments arguments) { + ExpressionTree firstArg = arguments.get(0); + while (firstArg.is(Tree.Kind.TYPE_CAST, Tree.Kind.MEMBER_SELECT, Tree.Kind.PARENTHESIZED_EXPRESSION)) { + firstArg = (ExpressionTree) CheckArgumentComplexType.getChildExpression(firstArg); + } + LiteralTree lit = (LiteralTree) firstArg; + return firstArg.is(Tree.Kind.FLOAT_LITERAL) + && Float.valueOf(lit.value()) <= 60.0f; } } \ No newline at end of file diff --git a/src/android-plugin/src/test/files/sobriety/HighFrameRateCheck.java b/src/android-plugin/src/test/files/sobriety/HighFrameRateCheck.java index 4fe1b1f92..428ccfec1 100644 --- a/src/android-plugin/src/test/files/sobriety/HighFrameRateCheck.java +++ b/src/android-plugin/src/test/files/sobriety/HighFrameRateCheck.java @@ -9,7 +9,10 @@ class Surface { public void test() { Surface surface = new Surface(); - surface.setFrameRate(0.0f,0); // Noncompliant {{Not overriding setFrameRate default behavior is recommanded to avoid higher battery usage.}} + surface.setFrameRate(0.0f,0); + surface.setFrameRate(60.0f,0); + surface.setFrameRate(90.0f,0); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} + surface.setFrameRate(120.0f,0); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} } public void setFrameRate(float frameRate, int compatibility) { From cb81eefddd00ed733917c1aafb368cf4439cbcc7 Mon Sep 17 00:00:00 2001 From: David Crescence Date: Fri, 3 Jun 2022 09:35:26 +0200 Subject: [PATCH 088/119] Adding java doc and fixing code smells. --- .../checks/sobriety/HighFrameRateRule.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java b/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java index e7ce0f3bf..47685b264 100644 --- a/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java +++ b/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java @@ -2,7 +2,6 @@ import com.google.common.collect.ImmutableList; import io.ecocode.java.checks.helpers.CheckArgumentComplexType; -import io.ecocode.java.checks.helpers.SpecificMethodCheck; import org.sonar.check.Rule; import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; import org.sonar.plugins.java.api.semantic.MethodMatchers; @@ -10,10 +9,11 @@ import java.util.List; -@Rule(key = "ESOB014", name= "ecoCodeHighFrameRate") +@Rule(key = "ESOB014", name = "ecoCodeHighFrameRate") public class HighFrameRateRule extends IssuableSubscriptionVisitor { - private final MethodMatchers surfaceListenerMethodMatcher = MethodMatchers.create().ofTypes("android.view.Surface").names("setFrameRate").withAnyParameters().build(); + private final MethodMatchers surfaceListenerMethodMatcher = MethodMatchers.create(). + ofTypes("android.view.Surface").names("setFrameRate").withAnyParameters().build(); public HighFrameRateRule() { super(); @@ -28,14 +28,18 @@ public List nodesToVisit() { public void visitNode(Tree tree) { if (tree.is(Tree.Kind.METHOD_INVOCATION)) { MethodInvocationTree methodInvocationTree = (MethodInvocationTree) tree; - if (surfaceListenerMethodMatcher.matches(methodInvocationTree)) { - if (!isRefreshSixtyOrLower(methodInvocationTree.arguments())) { - reportIssue(methodInvocationTree, "A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz."); - } + if (surfaceListenerMethodMatcher.matches(methodInvocationTree) && + !isRefreshSixtyOrLower(methodInvocationTree.arguments())) { + reportIssue(methodInvocationTree, "A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz."); } } } + /** + * Checking if method arguments are complying to the rule + * @param arguments Arguments of the method called + * @return true if argument is a float under or equal 60 + */ private boolean isRefreshSixtyOrLower(Arguments arguments) { ExpressionTree firstArg = arguments.get(0); while (firstArg.is(Tree.Kind.TYPE_CAST, Tree.Kind.MEMBER_SELECT, Tree.Kind.PARENTHESIZED_EXPRESSION)) { From fb7c9cc5b4b769ca9bc74028d8dfded9d92a801e Mon Sep 17 00:00:00 2001 From: David Crescence Date: Fri, 3 Jun 2022 10:45:57 +0200 Subject: [PATCH 089/119] Adding some tests for 3 args and flags. --- .../files/sobriety/HighFrameRateCheck.java | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/src/android-plugin/src/test/files/sobriety/HighFrameRateCheck.java b/src/android-plugin/src/test/files/sobriety/HighFrameRateCheck.java index 428ccfec1..7d8198e30 100644 --- a/src/android-plugin/src/test/files/sobriety/HighFrameRateCheck.java +++ b/src/android-plugin/src/test/files/sobriety/HighFrameRateCheck.java @@ -9,10 +9,36 @@ class Surface { public void test() { Surface surface = new Surface(); - surface.setFrameRate(0.0f,0); - surface.setFrameRate(60.0f,0); - surface.setFrameRate(90.0f,0); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} - surface.setFrameRate(120.0f,0); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} + surface.setFrameRate(0.0f, FRAME_RATE_COMPATIBILITY_DEFAULT); + surface.setFrameRate(60.0f, FRAME_RATE_COMPATIBILITY_DEFAULT); + surface.setFrameRate(90.0f, FRAME_RATE_COMPATIBILITY_DEFAULT); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} + surface.setFrameRate(120.0f, FRAME_RATE_COMPATIBILITY_DEFAULT); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} + // Test with compatibility fixed source + surface.setFrameRate(0.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE); + surface.setFrameRate(60.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE); + surface.setFrameRate(90.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} + surface.setFrameRate(120.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} + // Test with 3 args + surface.setFrameRate(0.0f, FRAME_RATE_COMPATIBILITY_DEFAULT, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); + surface.setFrameRate(60.0f, FRAME_RATE_COMPATIBILITY_DEFAULT, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); + surface.setFrameRate(90.0f, FRAME_RATE_COMPATIBILITY_DEFAULT, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} + surface.setFrameRate(120.0f, FRAME_RATE_COMPATIBILITY_DEFAULT, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} + + surface.setFrameRate(0.0f, FRAME_RATE_COMPATIBILITY_DEFAULT, CHANGE_FRAME_RATE_ALWAYS); + surface.setFrameRate(60.0f, FRAME_RATE_COMPATIBILITY_DEFAULT, CHANGE_FRAME_RATE_ALWAYS); + surface.setFrameRate(90.0f, FRAME_RATE_COMPATIBILITY_DEFAULT, CHANGE_FRAME_RATE_ALWAYS); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} + surface.setFrameRate(120.0f, FRAME_RATE_COMPATIBILITY_DEFAULT, CHANGE_FRAME_RATE_ALWAYS); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} + + surface.setFrameRate(0.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS); + surface.setFrameRate(60.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS); + surface.setFrameRate(90.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} + surface.setFrameRate(120.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} + + surface.setFrameRate(0.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); + surface.setFrameRate(60.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); + surface.setFrameRate(90.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} + surface.setFrameRate(120.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} + } public void setFrameRate(float frameRate, int compatibility) { From 3696921be773059f9a64c86954cdeb53f5554dfa Mon Sep 17 00:00:00 2001 From: David Crescence Date: Fri, 3 Jun 2022 12:16:35 +0200 Subject: [PATCH 090/119] Adding Identifier tests and fixing rulefor identifiers management. --- .../checks/sobriety/HighFrameRateRule.java | 21 ++++++++---- .../files/sobriety/HighFrameRateCheck.java | 32 ++++--------------- 2 files changed, 21 insertions(+), 32 deletions(-) diff --git a/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java b/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java index 47685b264..df40a1b03 100644 --- a/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java +++ b/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java @@ -12,6 +12,8 @@ @Rule(key = "ESOB014", name = "ecoCodeHighFrameRate") public class HighFrameRateRule extends IssuableSubscriptionVisitor { + private static final float FRAME_RATE_60 = 60.0f; + private final MethodMatchers surfaceListenerMethodMatcher = MethodMatchers.create(). ofTypes("android.view.Surface").names("setFrameRate").withAnyParameters().build(); @@ -29,7 +31,7 @@ public void visitNode(Tree tree) { if (tree.is(Tree.Kind.METHOD_INVOCATION)) { MethodInvocationTree methodInvocationTree = (MethodInvocationTree) tree; if (surfaceListenerMethodMatcher.matches(methodInvocationTree) && - !isRefreshSixtyOrLower(methodInvocationTree.arguments())) { + isRefreshSixtyOrHigher(methodInvocationTree.arguments())) { reportIssue(methodInvocationTree, "A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz."); } } @@ -40,13 +42,20 @@ public void visitNode(Tree tree) { * @param arguments Arguments of the method called * @return true if argument is a float under or equal 60 */ - private boolean isRefreshSixtyOrLower(Arguments arguments) { + private boolean isRefreshSixtyOrHigher(Arguments arguments) { ExpressionTree firstArg = arguments.get(0); - while (firstArg.is(Tree.Kind.TYPE_CAST, Tree.Kind.MEMBER_SELECT, Tree.Kind.PARENTHESIZED_EXPRESSION)) { + if (firstArg.is(Tree.Kind.IDENTIFIER)) { + IdentifierTree expressionTree = (IdentifierTree) firstArg; + Object argValue = expressionTree.asConstant().get(); + if (argValue instanceof Float) { + return ((Float) argValue).floatValue() > FRAME_RATE_60; + } + } else if (firstArg.is(Tree.Kind.FLOAT_LITERAL)) { firstArg = (ExpressionTree) CheckArgumentComplexType.getChildExpression(firstArg); + LiteralTree lit = (LiteralTree) firstArg; + return Float.valueOf(lit.value()) > FRAME_RATE_60; } - LiteralTree lit = (LiteralTree) firstArg; - return firstArg.is(Tree.Kind.FLOAT_LITERAL) - && Float.valueOf(lit.value()) <= 60.0f; + // not compliant case + return false; } } \ No newline at end of file diff --git a/src/android-plugin/src/test/files/sobriety/HighFrameRateCheck.java b/src/android-plugin/src/test/files/sobriety/HighFrameRateCheck.java index 7d8198e30..37e9e5834 100644 --- a/src/android-plugin/src/test/files/sobriety/HighFrameRateCheck.java +++ b/src/android-plugin/src/test/files/sobriety/HighFrameRateCheck.java @@ -6,37 +6,17 @@ class Surface { private static final int FRAME_RATE_COMPATIBILITY_FIXED_SOURCE = 1; private static final int CHANGE_FRAME_RATE_ALWAYS = 1; private static final int CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS = 0; + private static final float FRAME_RATE_0 = 0.0f; + private static final float FRAME_RATE_60 = 60.0f; + private static final float FRAME_RATE_90 = 90.0f; + private static final float FRAME_RATE_120 = 120.0f; public void test() { Surface surface = new Surface(); surface.setFrameRate(0.0f, FRAME_RATE_COMPATIBILITY_DEFAULT); - surface.setFrameRate(60.0f, FRAME_RATE_COMPATIBILITY_DEFAULT); - surface.setFrameRate(90.0f, FRAME_RATE_COMPATIBILITY_DEFAULT); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} - surface.setFrameRate(120.0f, FRAME_RATE_COMPATIBILITY_DEFAULT); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} - // Test with compatibility fixed source - surface.setFrameRate(0.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE); - surface.setFrameRate(60.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE); + surface.setFrameRate(FRAME_RATE_60, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); surface.setFrameRate(90.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} - surface.setFrameRate(120.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} - // Test with 3 args - surface.setFrameRate(0.0f, FRAME_RATE_COMPATIBILITY_DEFAULT, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); - surface.setFrameRate(60.0f, FRAME_RATE_COMPATIBILITY_DEFAULT, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); - surface.setFrameRate(90.0f, FRAME_RATE_COMPATIBILITY_DEFAULT, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} - surface.setFrameRate(120.0f, FRAME_RATE_COMPATIBILITY_DEFAULT, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} - - surface.setFrameRate(0.0f, FRAME_RATE_COMPATIBILITY_DEFAULT, CHANGE_FRAME_RATE_ALWAYS); - surface.setFrameRate(60.0f, FRAME_RATE_COMPATIBILITY_DEFAULT, CHANGE_FRAME_RATE_ALWAYS); - surface.setFrameRate(90.0f, FRAME_RATE_COMPATIBILITY_DEFAULT, CHANGE_FRAME_RATE_ALWAYS); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} - surface.setFrameRate(120.0f, FRAME_RATE_COMPATIBILITY_DEFAULT, CHANGE_FRAME_RATE_ALWAYS); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} - - surface.setFrameRate(0.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS); - surface.setFrameRate(60.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS); - surface.setFrameRate(90.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} - surface.setFrameRate(120.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} - - surface.setFrameRate(0.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); - surface.setFrameRate(60.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); - surface.setFrameRate(90.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} + surface.setFrameRate(FRAME_RATE_120, FRAME_RATE_COMPATIBILITY_DEFAULT); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} surface.setFrameRate(120.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} } From 168b1fea280bf3dddf48f499443fafe8d2122171 Mon Sep 17 00:00:00 2001 From: David Crescence Date: Fri, 3 Jun 2022 12:21:44 +0200 Subject: [PATCH 091/119] Cleaning code bug. --- .../io/ecocode/java/checks/sobriety/HighFrameRateRule.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java b/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java index df40a1b03..44871dddd 100644 --- a/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java +++ b/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java @@ -44,9 +44,8 @@ public void visitNode(Tree tree) { */ private boolean isRefreshSixtyOrHigher(Arguments arguments) { ExpressionTree firstArg = arguments.get(0); - if (firstArg.is(Tree.Kind.IDENTIFIER)) { - IdentifierTree expressionTree = (IdentifierTree) firstArg; - Object argValue = expressionTree.asConstant().get(); + if (firstArg.is(Tree.Kind.IDENTIFIER) && firstArg.asConstant().isPresent()) { + Object argValue = firstArg.asConstant().get(); if (argValue instanceof Float) { return ((Float) argValue).floatValue() > FRAME_RATE_60; } From 9fd5274563c4d352ea080824848c77df842691e4 Mon Sep 17 00:00:00 2001 From: David Crescence Date: Fri, 3 Jun 2022 12:29:25 +0200 Subject: [PATCH 092/119] Cleaning code bug. --- .../java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java b/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java index 44871dddd..f4cd0ece3 100644 --- a/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java +++ b/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java @@ -44,7 +44,7 @@ public void visitNode(Tree tree) { */ private boolean isRefreshSixtyOrHigher(Arguments arguments) { ExpressionTree firstArg = arguments.get(0); - if (firstArg.is(Tree.Kind.IDENTIFIER) && firstArg.asConstant().isPresent()) { + if (firstArg.asConstant().isPresent() && firstArg.is(Tree.Kind.IDENTIFIER)) { Object argValue = firstArg.asConstant().get(); if (argValue instanceof Float) { return ((Float) argValue).floatValue() > FRAME_RATE_60; From 099371404a6893889b7a38054cc3343e74a1d7a6 Mon Sep 17 00:00:00 2001 From: David Crescence Date: Fri, 3 Jun 2022 13:16:19 +0200 Subject: [PATCH 093/119] Adding optional unwrapping in test.. --- .../io/ecocode/java/checks/sobriety/HighFrameRateRule.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java b/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java index f4cd0ece3..105677a52 100644 --- a/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java +++ b/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java @@ -8,6 +8,7 @@ import org.sonar.plugins.java.api.tree.*; import java.util.List; +import java.util.Optional; @Rule(key = "ESOB014", name = "ecoCodeHighFrameRate") public class HighFrameRateRule extends IssuableSubscriptionVisitor { @@ -44,8 +45,9 @@ public void visitNode(Tree tree) { */ private boolean isRefreshSixtyOrHigher(Arguments arguments) { ExpressionTree firstArg = arguments.get(0); - if (firstArg.asConstant().isPresent() && firstArg.is(Tree.Kind.IDENTIFIER)) { - Object argValue = firstArg.asConstant().get(); + Optional argOptional = firstArg.asConstant(); + if (argOptional.isPresent() && firstArg.is(Tree.Kind.IDENTIFIER)) { + Object argValue = argOptional.get(); if (argValue instanceof Float) { return ((Float) argValue).floatValue() > FRAME_RATE_60; } From 150cdde3c7194152ac401e417bdc5afab76db740 Mon Sep 17 00:00:00 2001 From: David Crescence Date: Fri, 3 Jun 2022 13:28:41 +0200 Subject: [PATCH 094/119] Re adding more tests. --- .../files/sobriety/HighFrameRateCheck.java | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/android-plugin/src/test/files/sobriety/HighFrameRateCheck.java b/src/android-plugin/src/test/files/sobriety/HighFrameRateCheck.java index 37e9e5834..45e76dccb 100644 --- a/src/android-plugin/src/test/files/sobriety/HighFrameRateCheck.java +++ b/src/android-plugin/src/test/files/sobriety/HighFrameRateCheck.java @@ -14,11 +14,33 @@ class Surface { public void test() { Surface surface = new Surface(); surface.setFrameRate(0.0f, FRAME_RATE_COMPATIBILITY_DEFAULT); - surface.setFrameRate(FRAME_RATE_60, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); surface.setFrameRate(90.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} surface.setFrameRate(FRAME_RATE_120, FRAME_RATE_COMPATIBILITY_DEFAULT); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} - surface.setFrameRate(120.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} + // Test with compatibility fixed source + surface.setFrameRate(0.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE); + surface.setFrameRate(60.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE); + surface.setFrameRate(90.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} + surface.setFrameRate(120.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} + // Test with 3 args + surface.setFrameRate(0.0f, FRAME_RATE_COMPATIBILITY_DEFAULT, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); + surface.setFrameRate(60.0f, FRAME_RATE_COMPATIBILITY_DEFAULT, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); + surface.setFrameRate(90.0f, FRAME_RATE_COMPATIBILITY_DEFAULT, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} + surface.setFrameRate(120.0f, FRAME_RATE_COMPATIBILITY_DEFAULT, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} + + surface.setFrameRate(0.0f, FRAME_RATE_COMPATIBILITY_DEFAULT, CHANGE_FRAME_RATE_ALWAYS); + surface.setFrameRate(60.0f, FRAME_RATE_COMPATIBILITY_DEFAULT, CHANGE_FRAME_RATE_ALWAYS); + surface.setFrameRate(90.0f, FRAME_RATE_COMPATIBILITY_DEFAULT, CHANGE_FRAME_RATE_ALWAYS); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} + surface.setFrameRate(120.0f, FRAME_RATE_COMPATIBILITY_DEFAULT, CHANGE_FRAME_RATE_ALWAYS); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} + surface.setFrameRate(0.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS); + surface.setFrameRate(60.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS); + surface.setFrameRate(90.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} + surface.setFrameRate(120.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} + + surface.setFrameRate(0.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); + surface.setFrameRate(60.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); + surface.setFrameRate(90.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} + surface.setFrameRate(120.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} } public void setFrameRate(float frameRate, int compatibility) { From 66d3055745d269c5f3c404856f9026b11d1f56f0 Mon Sep 17 00:00:00 2001 From: David Crescence Date: Fri, 3 Jun 2022 14:28:04 +0200 Subject: [PATCH 095/119] Fixing constants for frame rate test. --- .../src/test/files/sobriety/HighFrameRateCheck.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/android-plugin/src/test/files/sobriety/HighFrameRateCheck.java b/src/android-plugin/src/test/files/sobriety/HighFrameRateCheck.java index 45e76dccb..cd10ac667 100644 --- a/src/android-plugin/src/test/files/sobriety/HighFrameRateCheck.java +++ b/src/android-plugin/src/test/files/sobriety/HighFrameRateCheck.java @@ -13,9 +13,11 @@ class Surface { public void test() { Surface surface = new Surface(); - surface.setFrameRate(0.0f, FRAME_RATE_COMPATIBILITY_DEFAULT); - surface.setFrameRate(90.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} - surface.setFrameRate(FRAME_RATE_120, FRAME_RATE_COMPATIBILITY_DEFAULT); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} + surface.setFrameRate(FRAME_RATE_0, FRAME_RATE_COMPATIBILITY_DEFAULT); + surface.setFrameRate(FRAME_RATE_60, FRAME_RATE_COMPATIBILITY_DEFAULT); + surface.setFrameRate(FRAME_RATE_90, FRAME_RATE_COMPATIBILITY_DEFAULT); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}}surface.setFrameRate(FRAME_RATE_120, FRAME_RATE_COMPATIBILITY_DEFAULT); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} + surface.setFrameRate(FRAME_RATE_120, FRAME_RATE_COMPATIBILITY_DEFAULT); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}}surface.setFrameRate(FRAME_RATE_120, FRAME_RATE_COMPATIBILITY_DEFAULT); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} + // Test with compatibility fixed source surface.setFrameRate(0.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE); surface.setFrameRate(60.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE); From fe37ec143584a3fef4acf861fa1b54093bd04b9c Mon Sep 17 00:00:00 2001 From: Antoine PRONNIER <44138938+FunixG@users.noreply.github.com> Date: Mon, 31 Oct 2022 14:09:52 +0100 Subject: [PATCH 096/119] [Rule-S75] Java Rule: Avoid Strings concatenation (#154) * [Rule-S75] Init new rule with unit tests & html definiton * [Rule-S75] Update RuleList * [Rule-S75] Update html hint sended to sonar * [Rule-S75] Done implementing java rule * [Rule-S75] Removed useless code * [Rule-S75] Updated rule severity and loop parser, WIP need fixing unit test failing * [Rule-S75] Refactoring code, removed useless if statements * [Rule-S75] Simplify binary visitor, wip tests * [Rule-S75] Rule done, changed visitor * [Rule-S75] Added new parsing method, for more flexibility (see tests) * [Rule-S75] Clean code Co-authored-by: oussamaLaribi <63214114+oussamaLaribi@users.noreply.github.com> --- .../main/java/fr/cnumr/java/RulesList.java | 1 + .../checks/AvoidConcatenateStringsInLoop.java | 63 +++++++++++++++++++ .../fr/cnumr/l10n/java/rules/java/S75.html | 41 ++++++++++++ .../fr/cnumr/l10n/java/rules/java/S75.json | 13 ++++ .../files/AvoidConcatenateStringsInLoop.java | 32 ++++++++++ .../files/GoodWayConcatenateStringsLoop.java | 33 ++++++++++ .../java/MyJavaFileCheckRegistrarTest.java | 3 +- .../AvoidConcatenateStringsInLoopTest.java | 24 +++++++ 8 files changed, 208 insertions(+), 2 deletions(-) create mode 100644 src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidConcatenateStringsInLoop.java create mode 100644 src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S75.html create mode 100644 src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S75.json create mode 100644 src/java-plugin/src/test/files/AvoidConcatenateStringsInLoop.java create mode 100644 src/java-plugin/src/test/files/GoodWayConcatenateStringsLoop.java create mode 100644 src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidConcatenateStringsInLoopTest.java diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java b/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java index 561221545..2fcaa323d 100644 --- a/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java +++ b/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java @@ -42,6 +42,7 @@ public static List> getChecks() { public static List> getJavaChecks() { return Collections.unmodifiableList(Arrays.asList( IncrementCheck.class, + AvoidConcatenateStringsInLoop.class, AvoidUsageOfStaticCollections.class, AvoidGettingSizeCollectionInLoop.class, AvoidRegexPatternNotStatic.class, diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidConcatenateStringsInLoop.java b/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidConcatenateStringsInLoop.java new file mode 100644 index 000000000..378524252 --- /dev/null +++ b/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidConcatenateStringsInLoop.java @@ -0,0 +1,63 @@ +package fr.cnumr.java.checks; + +import org.sonar.check.Priority; +import org.sonar.check.Rule; +import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; +import org.sonar.plugins.java.api.tree.*; + +import javax.annotation.Nonnull; +import java.util.Arrays; +import java.util.List; + +@Rule( + key = "S75", + name = "Developpement", + description = AvoidConcatenateStringsInLoop.MESSAGE_RULE, + priority = Priority.MINOR, + tags = {"bug"}) +public class AvoidConcatenateStringsInLoop extends IssuableSubscriptionVisitor { + + public static final String MESSAGE_RULE = "Don't concatenate Strings in loop, use StringBuilder instead."; + private static final String STRING_CLASS = String.class.getName(); + + private final StringConcatenationVisitor VISITOR = new StringConcatenationVisitor(); + + @Override + public List nodesToVisit() { + return Arrays.asList( + Tree.Kind.FOR_STATEMENT, + Tree.Kind.FOR_EACH_STATEMENT, + Tree.Kind.WHILE_STATEMENT + ); + } + + @Override + public void visitNode(@Nonnull Tree tree) { + tree.accept(VISITOR); + } + + private class StringConcatenationVisitor extends BaseTreeVisitor { + @Override + public void visitBinaryExpression(BinaryExpressionTree tree) { + if (tree.is(Tree.Kind.PLUS) && isStringType(tree.leftOperand())) { + reportIssue(tree, MESSAGE_RULE); + } else { + super.visitBinaryExpression(tree); + } + } + + @Override + public void visitAssignmentExpression(AssignmentExpressionTree tree) { + if (tree.is(Tree.Kind.PLUS_ASSIGNMENT) && isStringType(tree.variable())) { + reportIssue(tree, MESSAGE_RULE); + } else { + super.visitAssignmentExpression(tree); + } + } + } + + private boolean isStringType(ExpressionTree expressionTree) { + return expressionTree.symbolType().is(STRING_CLASS); + } + +} diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S75.html b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S75.html new file mode 100644 index 000000000..67c1c1ccf --- /dev/null +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S75.html @@ -0,0 +1,41 @@ +

+ Don't concatenate Strings in loop. User StringBuilder instead.
+ Strings are immutable so each time you concatenate a String, a new String is created. This is a waste of memory and CPU. +

+ +

Noncompliant Code Example

+
+
+    public String concatenateStrings(String[] strings) {
+        String result = "";
+
+        for (String string : strings) {
+            result += string; // Noncompliant
+        }
+        return result;
+    }
+
+    public String concatenateStrings2() {
+        String result = "";
+
+        for (int i = 0; i < 1000; ++i) {
+            result += "another"; // Noncompliant
+        }
+        return result;
+    }
+
+
+ +

Compliant Solution

+
+
+    public String concatenateStrings(String[] strings) {
+        StringBuilder result = new StringBuilder();
+
+        for (String string : strings) {
+            result.append(string);
+        }
+        return result.toString();
+    }
+
+
diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S75.json b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S75.json new file mode 100644 index 000000000..850703ab7 --- /dev/null +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S75.json @@ -0,0 +1,13 @@ +{ + "title": "Don't concatenate Strings in loop, use StringBuilder instead.", + "type": "CODE_SMELL", + "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "20min" + }, + "tags": [ + "eco-conception" + ], + "defaultSeverity": "Minor" +} diff --git a/src/java-plugin/src/test/files/AvoidConcatenateStringsInLoop.java b/src/java-plugin/src/test/files/AvoidConcatenateStringsInLoop.java new file mode 100644 index 000000000..7b50c1c13 --- /dev/null +++ b/src/java-plugin/src/test/files/AvoidConcatenateStringsInLoop.java @@ -0,0 +1,32 @@ +package fr.cnumr.java.utils; + +public class AvoidConcatenateStringsInLoop { + + public String concatenateStrings(String[] strings) { + String result1 = ""; + + for (String string : strings) { + result1 += string; // Noncompliant + } + return result1; + } + + public String concatenateStrings2() { + String result2 = ""; + + for (int i = 0; i < 1000; ++i) { + result2 += "another"; // Noncompliant + } + return result2; + } + + public String concatenateStrings3() { + String result3 = ""; + + for (int i = 0; i < 1000; ++i) { + result3 = result3 + "another"; // Noncompliant + } + return result3; + } + +} diff --git a/src/java-plugin/src/test/files/GoodWayConcatenateStringsLoop.java b/src/java-plugin/src/test/files/GoodWayConcatenateStringsLoop.java new file mode 100644 index 000000000..d6b9cebb2 --- /dev/null +++ b/src/java-plugin/src/test/files/GoodWayConcatenateStringsLoop.java @@ -0,0 +1,33 @@ +package fr.cnumr.java.utils; + +public class GoodWayConcatenateStringsLoop { + + public String concatenateStrings(String[] strings) { + StringBuilder result = new StringBuilder(); + + for (String string : strings) { + result.append(string); + } + return result.toString(); + } + + public void testConcateOutOfLoop() { + String result = ""; + result += "another"; + } + + public void testConcateOutOfLoop2() { + String result = ""; + result = result + "another"; + } + + public String changeValueStringInLoop() { + String result3 = ""; + + for (int i = 0; i < 1; ++i) { + result3 = "another"; + } + return result3; + } + +} diff --git a/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java b/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java index aeb839f49..0de5b693a 100644 --- a/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java +++ b/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java @@ -33,8 +33,7 @@ void checkNumberRules() { MyJavaFileCheckRegistrar registrar = new MyJavaFileCheckRegistrar(); registrar.register(context); - - assertThat(context.checkClasses()).hasSize(15); + assertThat(context.checkClasses()).hasSize(16); assertThat(context.testCheckClasses()).isEmpty(); } diff --git a/src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidConcatenateStringsInLoopTest.java b/src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidConcatenateStringsInLoopTest.java new file mode 100644 index 000000000..d21c1d09f --- /dev/null +++ b/src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidConcatenateStringsInLoopTest.java @@ -0,0 +1,24 @@ +package fr.cnumr.java.checks; + +import org.junit.jupiter.api.Test; +import org.sonar.java.checks.verifier.JavaCheckVerifier; + +public class AvoidConcatenateStringsInLoopTest { + + @Test + public void checkNonCompliantTests() { + JavaCheckVerifier.newVerifier() + .onFile("src/test/files/AvoidConcatenateStringsInLoop.java") + .withCheck(new AvoidConcatenateStringsInLoop()) + .verifyIssues(); + } + + @Test + public void checkCompliantTests() { + JavaCheckVerifier.newVerifier() + .onFile("src/test/files/GoodWayConcatenateStringsLoop.java") + .withCheck(new AvoidConcatenateStringsInLoop()) + .verifyNoIssues(); + } + +} From 8bced29b7390d2e3e7bb1f814d0ec81029aa0eed Mon Sep 17 00:00:00 2001 From: Julien Hertout Date: Mon, 31 Oct 2022 15:47:54 +0100 Subject: [PATCH 097/119] Android: High Frame Rate: update sonar issue short message and compliant code --- .../checks/sobriety/HighFrameRateRule.java | 2 +- .../l10n/java/rules/squid/ESOB014_java.html | 4 ---- .../files/sobriety/HighFrameRateCheck.java | 24 +++++++++---------- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java b/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java index 105677a52..f4a12296d 100644 --- a/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java +++ b/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java @@ -33,7 +33,7 @@ public void visitNode(Tree tree) { MethodInvocationTree methodInvocationTree = (MethodInvocationTree) tree; if (surfaceListenerMethodMatcher.matches(methodInvocationTree) && isRefreshSixtyOrHigher(methodInvocationTree.arguments())) { - reportIssue(methodInvocationTree, "A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz."); + reportIssue(methodInvocationTree, "To optimize content refresh and save energy, frame rate should be set at maximum 60Hz."); } } } diff --git a/src/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ESOB014_java.html b/src/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ESOB014_java.html index 16847c7f0..c0db8b22c 100644 --- a/src/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ESOB014_java.html +++ b/src/android-plugin/src/main/resources/org/sonar/l10n/java/rules/squid/ESOB014_java.html @@ -11,8 +11,4 @@

Noncompliant Code Example

Compliant Code Example

     surface.setFrameRate(60f, FRAME_RATE_COMPATIBILITY_DEFAULT);
-
-OR -
-    surface.setFrameRate(0f, FRAME_RATE_COMPATIBILITY_DEFAULT);
 
\ No newline at end of file diff --git a/src/android-plugin/src/test/files/sobriety/HighFrameRateCheck.java b/src/android-plugin/src/test/files/sobriety/HighFrameRateCheck.java index cd10ac667..ebdf0147e 100644 --- a/src/android-plugin/src/test/files/sobriety/HighFrameRateCheck.java +++ b/src/android-plugin/src/test/files/sobriety/HighFrameRateCheck.java @@ -15,34 +15,34 @@ public void test() { Surface surface = new Surface(); surface.setFrameRate(FRAME_RATE_0, FRAME_RATE_COMPATIBILITY_DEFAULT); surface.setFrameRate(FRAME_RATE_60, FRAME_RATE_COMPATIBILITY_DEFAULT); - surface.setFrameRate(FRAME_RATE_90, FRAME_RATE_COMPATIBILITY_DEFAULT); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}}surface.setFrameRate(FRAME_RATE_120, FRAME_RATE_COMPATIBILITY_DEFAULT); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} - surface.setFrameRate(FRAME_RATE_120, FRAME_RATE_COMPATIBILITY_DEFAULT); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}}surface.setFrameRate(FRAME_RATE_120, FRAME_RATE_COMPATIBILITY_DEFAULT); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} + surface.setFrameRate(FRAME_RATE_90, FRAME_RATE_COMPATIBILITY_DEFAULT); // Noncompliant {{To optimize content refresh and save energy, frame rate should be set at maximum 60Hz.}} + surface.setFrameRate(FRAME_RATE_120, FRAME_RATE_COMPATIBILITY_DEFAULT); // Noncompliant {{To optimize content refresh and save energy, frame rate should be set at maximum 60Hz.}} // Test with compatibility fixed source surface.setFrameRate(0.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE); surface.setFrameRate(60.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE); - surface.setFrameRate(90.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} - surface.setFrameRate(120.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} + surface.setFrameRate(90.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE); // Noncompliant {{To optimize content refresh and save energy, frame rate should be set at maximum 60Hz.}} + surface.setFrameRate(120.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE); // Noncompliant {{To optimize content refresh and save energy, frame rate should be set at maximum 60Hz.}} // Test with 3 args surface.setFrameRate(0.0f, FRAME_RATE_COMPATIBILITY_DEFAULT, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); surface.setFrameRate(60.0f, FRAME_RATE_COMPATIBILITY_DEFAULT, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); - surface.setFrameRate(90.0f, FRAME_RATE_COMPATIBILITY_DEFAULT, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} - surface.setFrameRate(120.0f, FRAME_RATE_COMPATIBILITY_DEFAULT, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} + surface.setFrameRate(90.0f, FRAME_RATE_COMPATIBILITY_DEFAULT, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); // Noncompliant {{To optimize content refresh and save energy, frame rate should be set at maximum 60Hz.}} + surface.setFrameRate(120.0f, FRAME_RATE_COMPATIBILITY_DEFAULT, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); // Noncompliant {{To optimize content refresh and save energy, frame rate should be set at maximum 60Hz.}} surface.setFrameRate(0.0f, FRAME_RATE_COMPATIBILITY_DEFAULT, CHANGE_FRAME_RATE_ALWAYS); surface.setFrameRate(60.0f, FRAME_RATE_COMPATIBILITY_DEFAULT, CHANGE_FRAME_RATE_ALWAYS); - surface.setFrameRate(90.0f, FRAME_RATE_COMPATIBILITY_DEFAULT, CHANGE_FRAME_RATE_ALWAYS); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} - surface.setFrameRate(120.0f, FRAME_RATE_COMPATIBILITY_DEFAULT, CHANGE_FRAME_RATE_ALWAYS); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} + surface.setFrameRate(90.0f, FRAME_RATE_COMPATIBILITY_DEFAULT, CHANGE_FRAME_RATE_ALWAYS); // Noncompliant {{To optimize content refresh and save energy, frame rate should be set at maximum 60Hz.}} + surface.setFrameRate(120.0f, FRAME_RATE_COMPATIBILITY_DEFAULT, CHANGE_FRAME_RATE_ALWAYS); // Noncompliant {{To optimize content refresh and save energy, frame rate should be set at maximum 60Hz.}} surface.setFrameRate(0.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS); surface.setFrameRate(60.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS); - surface.setFrameRate(90.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} - surface.setFrameRate(120.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} + surface.setFrameRate(90.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS); // Noncompliant {{To optimize content refresh and save energy, frame rate should be set at maximum 60Hz.}} + surface.setFrameRate(120.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS); // Noncompliant {{To optimize content refresh and save energy, frame rate should be set at maximum 60Hz.}} surface.setFrameRate(0.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); surface.setFrameRate(60.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); - surface.setFrameRate(90.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} - surface.setFrameRate(120.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); // Noncompliant {{A regular app displays 60 frames per second (60Hz). In order to optimize content refreshes and hence saving energy, this frequency should not be raised to 90Hz or 120Hz.}} + surface.setFrameRate(90.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); // Noncompliant {{To optimize content refresh and save energy, frame rate should be set at maximum 60Hz.}} + surface.setFrameRate(120.0f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); // Noncompliant {{To optimize content refresh and save energy, frame rate should be set at maximum 60Hz.}} } public void setFrameRate(float frameRate, int compatibility) { From 7007a12bbc1fdd10b5439b4b54894df0f0c43ab3 Mon Sep 17 00:00:00 2001 From: Julien Hertout Date: Mon, 31 Oct 2022 16:52:14 +0100 Subject: [PATCH 098/119] Android - Disable obfuscation: Minor update on documentation --- .../src/main/resources/org/sonar/plugins/groovy/rules.xml | 1 + src/codenarc-converter/CodeNarc/docs/codenarc-rules-ecocode.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/android-plugin/src/main/resources/org/sonar/plugins/groovy/rules.xml b/src/android-plugin/src/main/resources/org/sonar/plugins/groovy/rules.xml index 02dcaafea..b3521344c 100644 --- a/src/android-plugin/src/main/resources/org/sonar/plugins/groovy/rules.xml +++ b/src/android-plugin/src/main/resources/org/sonar/plugins/groovy/rules.xml @@ -84,6 +84,7 @@ code-smell + org.codenarc.rule.ecocode.DisableObfuscationRule MINOR diff --git a/src/codenarc-converter/CodeNarc/docs/codenarc-rules-ecocode.md b/src/codenarc-converter/CodeNarc/docs/codenarc-rules-ecocode.md index 7bdda726b..863dff5ce 100644 --- a/src/codenarc-converter/CodeNarc/docs/codenarc-rules-ecocode.md +++ b/src/codenarc-converter/CodeNarc/docs/codenarc-rules-ecocode.md @@ -85,7 +85,7 @@ android { ## DisableObfuscation Rule -*Since CodeNarc 2.2.1* +*Since CodeNarc 2.2.2* Using minifyEnabled true will obfuscate code and will have a sligthly negative impact on power consumption at runtime. From d75cd3ad6a386c5fd15679bbfbb8c21f3760518a Mon Sep 17 00:00:00 2001 From: Julien Hertout Date: Wed, 2 Nov 2022 07:26:57 +0100 Subject: [PATCH 099/119] Update CodeNarc version to 2.2.3 since we add a new rule (Disable Obfuscation) --- src/android-plugin/pom.xml | 2 +- .../src/main/resources/org/sonar/plugins/groovy/rules.xml | 2 +- src/codenarc-converter/CodeNarc/CHANGELOG.md | 5 +++++ src/codenarc-converter/CodeNarc/build.gradle | 2 +- .../CodeNarc/docs/codenarc-rules-ecocode.md | 2 +- .../CodeNarc/src/main/resources/codenarc-version.txt | 2 +- src/codenarc-converter/pom.xml | 2 +- src/prepare-codenarc | 2 +- src/prepare-codenarc.bat | 2 +- 9 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/android-plugin/pom.xml b/src/android-plugin/pom.xml index 1c01a6218..cfc75b6c5 100644 --- a/src/android-plugin/pom.xml +++ b/src/android-plugin/pom.xml @@ -191,7 +191,7 @@ org.codenarc CodeNarc - 2.2.2 + 2.2.3 org.gmetrics diff --git a/src/android-plugin/src/main/resources/org/sonar/plugins/groovy/rules.xml b/src/android-plugin/src/main/resources/org/sonar/plugins/groovy/rules.xml index b3521344c..acbdffb84 100644 --- a/src/android-plugin/src/main/resources/org/sonar/plugins/groovy/rules.xml +++ b/src/android-plugin/src/main/resources/org/sonar/plugins/groovy/rules.xml @@ -84,7 +84,7 @@ code-smell - + org.codenarc.rule.ecocode.DisableObfuscationRule MINOR diff --git a/src/codenarc-converter/CodeNarc/CHANGELOG.md b/src/codenarc-converter/CodeNarc/CHANGELOG.md index 0c1280b18..dcaa1a4b9 100644 --- a/src/codenarc-converter/CodeNarc/CHANGELOG.md +++ b/src/codenarc-converter/CodeNarc/CHANGELOG.md @@ -5,6 +5,11 @@ # CodeNarc Change Log +Version 2.2.3 (November 2022) +-------------------------------------- +Build and Infrastructure +- Upgrade Gradle to wrapper 6.9.2 (avoid Log4Shell vulnerability) + Version 2.2.2 (May 2022) -------------------------------------- Build and Infrastructure diff --git a/src/codenarc-converter/CodeNarc/build.gradle b/src/codenarc-converter/CodeNarc/build.gradle index 13b8d0a90..0b2194168 100644 --- a/src/codenarc-converter/CodeNarc/build.gradle +++ b/src/codenarc-converter/CodeNarc/build.gradle @@ -14,7 +14,7 @@ shadowJar { group = 'org.codenarc' archivesBaseName = 'CodeNarc' -version = '2.2.2' +version = '2.2.3' sourceCompatibility = '1.7' targetCompatibility = '1.7' diff --git a/src/codenarc-converter/CodeNarc/docs/codenarc-rules-ecocode.md b/src/codenarc-converter/CodeNarc/docs/codenarc-rules-ecocode.md index 863dff5ce..516dcf8b3 100644 --- a/src/codenarc-converter/CodeNarc/docs/codenarc-rules-ecocode.md +++ b/src/codenarc-converter/CodeNarc/docs/codenarc-rules-ecocode.md @@ -85,7 +85,7 @@ android { ## DisableObfuscation Rule -*Since CodeNarc 2.2.2* +*Since CodeNarc 2.2.3* Using minifyEnabled true will obfuscate code and will have a sligthly negative impact on power consumption at runtime. diff --git a/src/codenarc-converter/CodeNarc/src/main/resources/codenarc-version.txt b/src/codenarc-converter/CodeNarc/src/main/resources/codenarc-version.txt index b1b25a5ff..585940699 100644 --- a/src/codenarc-converter/CodeNarc/src/main/resources/codenarc-version.txt +++ b/src/codenarc-converter/CodeNarc/src/main/resources/codenarc-version.txt @@ -1 +1 @@ -2.2.2 +2.2.3 diff --git a/src/codenarc-converter/pom.xml b/src/codenarc-converter/pom.xml index 8952c6c76..e90cb7578 100644 --- a/src/codenarc-converter/pom.xml +++ b/src/codenarc-converter/pom.xml @@ -13,7 +13,7 @@ Sonar CodeNarc Converter - 2.2.2 + 2.2.3 1.8.2 true diff --git a/src/prepare-codenarc b/src/prepare-codenarc index bd1257ff8..ee9582001 100755 --- a/src/prepare-codenarc +++ b/src/prepare-codenarc @@ -1,7 +1,7 @@ #!/usr/bin/env sh # Define CodeNarc version -codenarcVersion="2.2.2" +codenarcVersion="2.2.3" # Build CodeNarc cd codenarc-converter/CodeNarc diff --git a/src/prepare-codenarc.bat b/src/prepare-codenarc.bat index 53bce432e..0890818bd 100644 --- a/src/prepare-codenarc.bat +++ b/src/prepare-codenarc.bat @@ -1,5 +1,5 @@ REM == Define CodeNarc version -set codenarc_version=2.2.2 +set codenarc_version=2.2.3 REM == Build CodeNarc cd codenarc-converter/CodeNarc From 076c4de955b8fd168683dffa815e4321a3f515c0 Mon Sep 17 00:00:00 2001 From: Julien Hertout Date: Wed, 2 Nov 2022 07:27:31 +0100 Subject: [PATCH 100/119] Slightly improve Android readme for clarity --- src/android-plugin/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/android-plugin/README.md b/src/android-plugin/README.md index c2e2ef6cd..3e30e1f11 100644 --- a/src/android-plugin/README.md +++ b/src/android-plugin/README.md @@ -43,6 +43,7 @@ Tests are located under: Build CodeNarc (gradle 6.9.2, Java 11): ```sh +cd /codenarc-converter/CodeNarc ./gradlew build -x test ``` From 5830a41d4200f93c9dd7dcf7d4893bedc687c323 Mon Sep 17 00:00:00 2001 From: Julien Hertout Date: Wed, 2 Nov 2022 07:33:48 +0100 Subject: [PATCH 101/119] Improve CodeNarc changelog for 2.2.1 and 2.2.3 by indicating added rules --- src/codenarc-converter/CodeNarc/CHANGELOG.md | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/codenarc-converter/CodeNarc/CHANGELOG.md b/src/codenarc-converter/CodeNarc/CHANGELOG.md index dcaa1a4b9..3f83a198a 100644 --- a/src/codenarc-converter/CodeNarc/CHANGELOG.md +++ b/src/codenarc-converter/CodeNarc/CHANGELOG.md @@ -1,26 +1,22 @@ -#TODO: Sort the following line into the file -- FatApp rule (ecocode) - Using "multiDexEnabled true" goes against the overall reduction of the weight of the apps and hence must be avoided. - # CodeNarc Change Log Version 2.2.3 (November 2022) -------------------------------------- -Build and Infrastructure -- Upgrade Gradle to wrapper 6.9.2 (avoid Log4Shell vulnerability) +Added rule +- ecoCode: Disable Obfuscation Version 2.2.2 (May 2022) -------------------------------------- Build and Infrastructure - Upgrade Gradle to wrapper 6.9.2 (avoid Log4Shell vulnerability) - Version 2.2.1 (Mar 2022) -------------------------------------- -Updated/Enhanced Rules and Bug Fixes -- Add ecoCode rules - +Added rules +- ecoCode: Fat App +- ecoCode: Supported Version Range Version 2.2.0 (Aug 2021) -------------------------------------- From 0e49a2b92c4a76bbbe26b70036fe0ce15db4aa3e Mon Sep 17 00:00:00 2001 From: hugodezordo <55738275+hugodezordo@users.noreply.github.com> Date: Wed, 2 Nov 2022 15:24:04 +0100 Subject: [PATCH 102/119] [Rule-S79] test and rule free resources of auto closeable interface (#165) * [Rule-S79] test and rule free resources of auto closeable interface * Fix sonar code smells * Chnage rules size to 17 * Change size to 17 * Adapt the description of the rule Co-authored-by: oussamaLaribi <63214114+oussamaLaribi@users.noreply.github.com> --- .../main/java/fr/cnumr/java/RulesList.java | 3 +- ...FreeResourcesOfAutoCloseableInterface.java | 76 +++++++++++++++++++ .../fr/cnumr/l10n/java/rules/java/S79.html | 24 ++++++ .../fr/cnumr/l10n/java/rules/java/S79.json | 13 ++++ ...FreeResourcesOfAutoCloseableInterface.java | 37 +++++++++ .../java/MyJavaFileCheckRegistrarTest.java | 2 +- ...ResourcesOfAutoCloseableInterfaceTest.java | 24 ++++++ 7 files changed, 177 insertions(+), 2 deletions(-) create mode 100644 src/java-plugin/src/main/java/fr/cnumr/java/checks/FreeResourcesOfAutoCloseableInterface.java create mode 100644 src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S79.html create mode 100644 src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S79.json create mode 100644 src/java-plugin/src/test/files/FreeResourcesOfAutoCloseableInterface.java create mode 100644 src/java-plugin/src/test/java/fr/cnumr/java/checks/FreeResourcesOfAutoCloseableInterfaceTest.java diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java b/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java index 2fcaa323d..cb36feae7 100644 --- a/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java +++ b/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java @@ -56,7 +56,8 @@ public static List> getJavaChecks() { OptimizeReadFileExceptions.class, InitializeBufferWithAppropriateSize.class, AvoidUsingGlobalVariablesCheck.class, - AvoidSetConstantInBatchUpdate.class + AvoidSetConstantInBatchUpdate.class, + FreeResourcesOfAutoCloseableInterface.class )); } diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/checks/FreeResourcesOfAutoCloseableInterface.java b/src/java-plugin/src/main/java/fr/cnumr/java/checks/FreeResourcesOfAutoCloseableInterface.java new file mode 100644 index 000000000..fa314116b --- /dev/null +++ b/src/java-plugin/src/main/java/fr/cnumr/java/checks/FreeResourcesOfAutoCloseableInterface.java @@ -0,0 +1,76 @@ +package fr.cnumr.java.checks; + +import org.sonar.check.Priority; +import org.sonar.check.Rule; +import org.sonar.java.JavaVersionAwareVisitor; +import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; +import org.sonar.plugins.java.api.JavaFileScannerContext; +import org.sonar.plugins.java.api.JavaVersion; +import org.sonar.plugins.java.api.tree.NewClassTree; +import org.sonar.plugins.java.api.tree.Tree; +import org.sonar.plugins.java.api.tree.TryStatementTree; + +import javax.annotation.ParametersAreNonnullByDefault; +import java.util.*; + + +@Rule( + key = "S79", + name = "Developpement", + description = FreeResourcesOfAutoCloseableInterface.MESSAGE_RULE, + priority = Priority.MINOR, + tags = {"bug"}) +public class FreeResourcesOfAutoCloseableInterface extends IssuableSubscriptionVisitor implements JavaVersionAwareVisitor { + private final Deque withinTry = new LinkedList<>(); + private final Deque> toReport = new LinkedList<>(); + + private static final String JAVA_LANG_AUTOCLOSEABLE = "java.lang.AutoCloseable"; + protected static final String MESSAGE_RULE = "try-with-resources Statement needs to be implemented for any object that implements the AutoClosable interface."; + + @Override + @ParametersAreNonnullByDefault + public void leaveFile(JavaFileScannerContext context) { + withinTry.clear(); + toReport.clear(); + } + + @Override + public List nodesToVisit() { + return Arrays.asList(Tree.Kind.TRY_STATEMENT, Tree.Kind.NEW_CLASS); + } + + @Override + public void visitNode(Tree tree) { + if (tree.is(Tree.Kind.TRY_STATEMENT)) { + withinTry.push((TryStatementTree) tree); + if (withinTry.size() != toReport.size()) { + toReport.push(new ArrayList<>()); + } + } + if (tree.is(Tree.Kind.NEW_CLASS) && ((NewClassTree) tree).symbolType().isSubtypeOf(JAVA_LANG_AUTOCLOSEABLE) && withinStandardTryWithFinally() ) { + assert toReport.peek() != null; + toReport.peek().add(tree); + } + } + + @Override + public void leaveNode(Tree tree) { + if (tree.is(Tree.Kind.TRY_STATEMENT)) { + List secondaryTrees = toReport.pop(); + if (!secondaryTrees.isEmpty()) { + reportIssue(tree, MESSAGE_RULE); + } + } + } + + private boolean withinStandardTryWithFinally() { + if (withinTry.isEmpty() || !withinTry.peek().resourceList().isEmpty()) return false; + assert withinTry.peek() != null; + return withinTry.peek().finallyBlock() != null; + } + + @Override + public boolean isCompatibleWithJavaVersion(JavaVersion version) { + return version.isJava7Compatible(); + } +} diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S79.html b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S79.html new file mode 100644 index 000000000..f8801ef21 --- /dev/null +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S79.html @@ -0,0 +1,24 @@ +

try-with-resources Statement needs to be implemented for any object that implements the AutoCloseable interface, it save computer resources.

+

Noncompliant Code Example

+
+    private static void printFileJava7() throws IOException {
+        FileInputStream input = new FileInputStream("file.txt");
+        int data = input.read();
+        while(data != -1){
+            System.out.print((char) data);
+            data = input.read();
+        }
+    }
+
+

Compliant Solution

+
+    private static void printFileJava7() throws IOException {
+        try(FileInputStream input = new FileInputStream("file.txt")) {
+            int data = input.read();
+            while(data != -1){
+                System.out.print((char) data);
+                data = input.read();
+            }
+        }
+    }
+
diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S79.json b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S79.json new file mode 100644 index 000000000..0493a47b5 --- /dev/null +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/S79.json @@ -0,0 +1,13 @@ +{ + "title": "Free resources", + "type": "CODE_SMELL", + "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "15min" + }, + "tags": [ + "eco-conception" + ], + "defaultSeverity": "Minor" +} \ No newline at end of file diff --git a/src/java-plugin/src/test/files/FreeResourcesOfAutoCloseableInterface.java b/src/java-plugin/src/test/files/FreeResourcesOfAutoCloseableInterface.java new file mode 100644 index 000000000..b29dfec4d --- /dev/null +++ b/src/java-plugin/src/test/files/FreeResourcesOfAutoCloseableInterface.java @@ -0,0 +1,37 @@ +package fr.cnumr.java.checks; + +import java.io.*; + +class FreeResourcesOfAutoCloseableInterface { + FreeResourcesOfAutoCloseableInterface(FreeResourcesOfAutoCloseableInterface mc) { + + } + + public void foo1() { + String fileName = "./FreeResourcesOfAutoCloseableInterface.java"; + try (FileReader fr = new FileReader(fileName); + BufferedReader br = new BufferedReader(fr)) { + } + catch (IOException e) { + System.err.println(e.getMessage()); + } + } + + public void foo2() { + String fileName = "./FreeResourcesOfAutoCloseableInterface.java"; + try { // Noncompliant + FileReader fr = new FileReader(fileName); + BufferedReader br = new BufferedReader(fr); + System.out.printl(br.readLine()); + } catch (IOException e) { + System.err.println(e.getMessage()); + } finally { + if (fr) { + fr.close(); + } + if (br) { + br.close(); + } + } + } +} \ No newline at end of file diff --git a/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java b/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java index 0de5b693a..b699f1e0c 100644 --- a/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java +++ b/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java @@ -33,7 +33,7 @@ void checkNumberRules() { MyJavaFileCheckRegistrar registrar = new MyJavaFileCheckRegistrar(); registrar.register(context); - assertThat(context.checkClasses()).hasSize(16); + assertThat(context.checkClasses()).hasSize(17); assertThat(context.testCheckClasses()).isEmpty(); } diff --git a/src/java-plugin/src/test/java/fr/cnumr/java/checks/FreeResourcesOfAutoCloseableInterfaceTest.java b/src/java-plugin/src/test/java/fr/cnumr/java/checks/FreeResourcesOfAutoCloseableInterfaceTest.java new file mode 100644 index 000000000..d7e9691ee --- /dev/null +++ b/src/java-plugin/src/test/java/fr/cnumr/java/checks/FreeResourcesOfAutoCloseableInterfaceTest.java @@ -0,0 +1,24 @@ +package fr.cnumr.java.checks; + +import org.junit.jupiter.api.Test; +import org.sonar.java.checks.verifier.JavaCheckVerifier; + +class FreeResourcesOfAutoCloseableInterfaceTest { + + @Test + void test() { + JavaCheckVerifier.newVerifier() + .onFile("src/test/files/FreeResourcesOfAutoCloseableInterface.java") + .withCheck(new FreeResourcesOfAutoCloseableInterface()) + .withJavaVersion(7) + .verifyIssues(); + } + + @Test + void test_no_java_version() { + JavaCheckVerifier.newVerifier() + .onFile("src/test/files/FreeResourcesOfAutoCloseableInterface.java") + .withCheck(new FreeResourcesOfAutoCloseableInterface()) + .verifyIssues(); + } +} \ No newline at end of file From 4ee08110a0fc384f8abde5f74370b70cee1f6b91 Mon Sep 17 00:00:00 2001 From: oussamaLaribi <63214114+oussamaLaribi@users.noreply.github.com> Date: Fri, 4 Nov 2022 10:56:18 +0100 Subject: [PATCH 103/119] Fix sonar error can't find class --- .../java/checks/FreeResourcesOfAutoCloseableInterface.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/checks/FreeResourcesOfAutoCloseableInterface.java b/src/java-plugin/src/main/java/fr/cnumr/java/checks/FreeResourcesOfAutoCloseableInterface.java index fa314116b..1c8a685b6 100644 --- a/src/java-plugin/src/main/java/fr/cnumr/java/checks/FreeResourcesOfAutoCloseableInterface.java +++ b/src/java-plugin/src/main/java/fr/cnumr/java/checks/FreeResourcesOfAutoCloseableInterface.java @@ -2,7 +2,6 @@ import org.sonar.check.Priority; import org.sonar.check.Rule; -import org.sonar.java.JavaVersionAwareVisitor; import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; import org.sonar.plugins.java.api.JavaFileScannerContext; import org.sonar.plugins.java.api.JavaVersion; @@ -20,7 +19,7 @@ description = FreeResourcesOfAutoCloseableInterface.MESSAGE_RULE, priority = Priority.MINOR, tags = {"bug"}) -public class FreeResourcesOfAutoCloseableInterface extends IssuableSubscriptionVisitor implements JavaVersionAwareVisitor { +public class FreeResourcesOfAutoCloseableInterface extends IssuableSubscriptionVisitor { private final Deque withinTry = new LinkedList<>(); private final Deque> toReport = new LinkedList<>(); @@ -69,7 +68,6 @@ private boolean withinStandardTryWithFinally() { return withinTry.peek().finallyBlock() != null; } - @Override public boolean isCompatibleWithJavaVersion(JavaVersion version) { return version.isJava7Compatible(); } From ae8a56b1828f671b60b3c3b2f78e7f76bae5d72c Mon Sep 17 00:00:00 2001 From: Mohamed SALHAOUI <50855585+med-S@users.noreply.github.com> Date: Mon, 7 Nov 2022 11:15:03 +0100 Subject: [PATCH 104/119] Delete .idea directory --- .idea/.gitignore | 8 --- .idea/ecoCode.iml | 9 ---- .idea/inspectionProfiles/Project_Default.xml | 6 --- .idea/misc.xml | 4 -- .idea/modules.xml | 8 --- .idea/vcs.xml | 6 --- .idea/workspace.xml | 55 -------------------- 7 files changed, 96 deletions(-) delete mode 100644 .idea/.gitignore delete mode 100644 .idea/ecoCode.iml delete mode 100644 .idea/inspectionProfiles/Project_Default.xml delete mode 100644 .idea/misc.xml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/vcs.xml delete mode 100644 .idea/workspace.xml diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 13566b81b..000000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Editor-based HTTP Client requests -/httpRequests/ -# Datasource local storage ignored files -/dataSources/ -/dataSources.local.xml diff --git a/.idea/ecoCode.iml b/.idea/ecoCode.iml deleted file mode 100644 index d6ebd4805..000000000 --- a/.idea/ecoCode.iml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml deleted file mode 100644 index ac21435ff..000000000 --- a/.idea/inspectionProfiles/Project_Default.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 412cda9dd..000000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 648097b9c..000000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 35eb1ddfb..000000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml deleted file mode 100644 index 4770f957b..000000000 --- a/.idea/workspace.xml +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - 1654173028185 - - - - - - - \ No newline at end of file From b43344fdd8ad3013130bccc20ab0419edafbaa15 Mon Sep 17 00:00:00 2001 From: Mohamed SALHAOUI <50855585+med-S@users.noreply.github.com> Date: Mon, 7 Nov 2022 11:44:09 +0100 Subject: [PATCH 105/119] Update ArrayCopyCheck.java --- .../fr/cnumr/java/checks/ArrayCopyCheck.java | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/checks/ArrayCopyCheck.java b/src/java-plugin/src/main/java/fr/cnumr/java/checks/ArrayCopyCheck.java index 9150318e8..59d77ce81 100644 --- a/src/java-plugin/src/main/java/fr/cnumr/java/checks/ArrayCopyCheck.java +++ b/src/java-plugin/src/main/java/fr/cnumr/java/checks/ArrayCopyCheck.java @@ -149,17 +149,22 @@ private boolean isVariable(final ExpressionTree source) { private List getBlocsOfCode(final Tree tree) { final List blocs = new ArrayList<>(); if (tree instanceof ForStatementTree) { - addBloc(blocs, ((ForStatementTree) tree).statement()); + ForStatementTree castedForTree = (ForStatementTree) tree; + addBloc(blocs, castedForTree.statement()); } else if (tree instanceof ForEachStatement) { - addForEachBloc(blocs, ((ForEachStatement) tree).statement(), ((ForEachStatement) tree).variable(), - ((ForEachStatement) tree).expression()); + ForEachStatement castedForEachTree = (ForEachStatement) tree; + addForEachBloc(blocs, castedForEachTree.statement(), castedForEachTree.variable(), + castedForEachTree.expression()); } else if (tree instanceof WhileStatementTree) { - addBloc(blocs, ((WhileStatementTree) tree).statement()); + WhileStatementTree castedWhileTree = (WhileStatementTree) tree; + addBloc(blocs, castedWhileTree.statement()); } else if (tree instanceof DoWhileStatementTree) { - addBloc(blocs, ((DoWhileStatementTree) tree).statement()); + DoWhileStatementTree castedDoWhileTree = (DoWhileStatementTree) tree; + addBloc(blocs, castedDoWhileTree.statement()); } else if (tree instanceof IfStatementTree) { - addBloc(blocs, ((IfStatementTree) tree).thenStatement()); - addBloc(blocs, ((IfStatementTree) tree).elseStatement()); + IfStatementTree castedIfTree = (IfStatementTree) tree; + addBloc(blocs, castedIfTree.thenStatement()); + addBloc(blocs, castedIfTree.elseStatement()); } else if (tree instanceof TryStatementTree) { final TryStatementTree tryTree = (TryStatementTree) tree; addBloc(blocs, tryTree.block()); From 828361f8884a6930864ebf3b7506afd2f5be0956 Mon Sep 17 00:00:00 2001 From: Mohamed SALHAOUI <50855585+med-S@users.noreply.github.com> Date: Mon, 7 Nov 2022 11:46:08 +0100 Subject: [PATCH 106/119] Update MyJavaFileCheckRegistrarTest.java --- .../test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java b/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java index b7e339ce2..fb368adee 100644 --- a/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java +++ b/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java @@ -34,7 +34,7 @@ void checkNumberRules() { final MyJavaFileCheckRegistrar registrar = new MyJavaFileCheckRegistrar(); registrar.register(context); - assertThat(context.checkClasses()).hasSize(17); + assertThat(context.checkClasses()).hasSize(18); assertThat(context.testCheckClasses()).isEmpty(); } } From bea3ea344ee8ab678341153c1a33478c674dc51a Mon Sep 17 00:00:00 2001 From: MP-Aubay Date: Mon, 7 Nov 2022 15:46:07 +0100 Subject: [PATCH 107/119] feat - Migrate Java compilation from 8 to 11 (#167) --- hackathon/starter-pack.md | 2 +- src/INSTALL.md | 2 +- src/android-plugin/pom.xml | 4 ++-- src/java-plugin/pom.xml | 4 ++-- src/php-plugin/pom.xml | 4 ++-- src/pom.xml | 4 ++-- src/python-plugin/pom.xml | 4 ++-- src/xml-plugin/pom.xml | 4 ++-- 8 files changed, 14 insertions(+), 14 deletions(-) diff --git a/hackathon/starter-pack.md b/hackathon/starter-pack.md index 21e1e3794..71b70a5fa 100644 --- a/hackathon/starter-pack.md +++ b/hackathon/starter-pack.md @@ -34,7 +34,7 @@ You will need to install Docker : https://docs.docker.com/get-docker/ Docker-compose 3.9 : https://docs.docker.com/compose/install/ -Java >=8 for Sonarqube plugin Development : https://www.java.com/fr/download/manual.jsp +Java >=11 for Sonarqube plugin Development : https://www.java.com/fr/download/manual.jsp Maven 3 for Sonarqube plugin Development : https://maven.apache.org/download.cgi diff --git a/src/INSTALL.md b/src/INSTALL.md index 0a09bb220..75305c82f 100644 --- a/src/INSTALL.md +++ b/src/INSTALL.md @@ -29,7 +29,7 @@ You will find more information about the plugins’ architecture in their folder ### Prerequisites -- Java >= 8 +- Java >= 11 - Mvn 3 diff --git a/src/android-plugin/pom.xml b/src/android-plugin/pom.xml index cfc75b6c5..6d80f8645 100644 --- a/src/android-plugin/pom.xml +++ b/src/android-plugin/pom.xml @@ -271,8 +271,8 @@ maven-compiler-plugin 3.6.0 - 1.8 - 1.8 + 11 + 11 diff --git a/src/java-plugin/pom.xml b/src/java-plugin/pom.xml index d2ee279ef..32a156b4c 100644 --- a/src/java-plugin/pom.xml +++ b/src/java-plugin/pom.xml @@ -118,8 +118,8 @@ maven-compiler-plugin 3.8.0 - 1.8 - 1.8 + 11 + 11 diff --git a/src/php-plugin/pom.xml b/src/php-plugin/pom.xml index 9d998b3cc..d595e0a25 100644 --- a/src/php-plugin/pom.xml +++ b/src/php-plugin/pom.xml @@ -79,8 +79,8 @@ maven-compiler-plugin 3.6.0 - 1.8 - 1.8 + 11 + 11 diff --git a/src/pom.xml b/src/pom.xml index 112dff9f4..d8a9491aa 100644 --- a/src/pom.xml +++ b/src/pom.xml @@ -74,8 +74,8 @@ UTF-8 - 1.8 - 1.8 + 11 + 11 cnumr-1 https://sonarcloud.io diff --git a/src/python-plugin/pom.xml b/src/python-plugin/pom.xml index 7ed2f4244..f02362783 100644 --- a/src/python-plugin/pom.xml +++ b/src/python-plugin/pom.xml @@ -86,8 +86,8 @@ maven-compiler-plugin 3.7.0 - 1.8 - 1.8 + 11 + 11 diff --git a/src/xml-plugin/pom.xml b/src/xml-plugin/pom.xml index 0d91c8804..e1e71dea7 100644 --- a/src/xml-plugin/pom.xml +++ b/src/xml-plugin/pom.xml @@ -92,8 +92,8 @@ maven-compiler-plugin 3.6.0 - 1.8 - 1.8 + 11 + 11 From 71ce88812bd3e0b209867e41db1ecb5118f9cf25 Mon Sep 17 00:00:00 2001 From: Mohamed SALHAOUI <50855585+med-S@users.noreply.github.com> Date: Tue, 8 Nov 2022 13:46:09 +0100 Subject: [PATCH 108/119] Update BrightnessOverrideRule.java Fix this call that leads to an illegal type cast --- .../ecocode/java/checks/sobriety/BrightnessOverrideRule.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/BrightnessOverrideRule.java b/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/BrightnessOverrideRule.java index 76c29abcd..562464b5a 100644 --- a/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/BrightnessOverrideRule.java +++ b/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/BrightnessOverrideRule.java @@ -105,8 +105,8 @@ private boolean isBrightnessAssignment(AssignmentExpressionTree assignmentExpres } private void checkBrightnessAssignmentExpressionValue(Tree tree, String qualifiedType, Number value) { - if (qualifiedType.equals("float") && (Float) value == BRIGHTNESS_FULL_VALUE - || qualifiedType.equals("int") && (Integer) value == BRIGHTNESS_FULL_VALUE) { + if (qualifiedType.equals("float") && value.folatValue() == BRIGHTNESS_FULL_VALUE + || qualifiedType.equals("int") && value.intValue() == BRIGHTNESS_FULL_VALUE) { reportIssue(tree, ERROR_MESSAGE); } } From 9451e1f2903885d78b93d66dfc243b732287ba6b Mon Sep 17 00:00:00 2001 From: Mohamed SALHAOUI <50855585+med-S@users.noreply.github.com> Date: Tue, 8 Nov 2022 13:55:00 +0100 Subject: [PATCH 109/119] Update BrightnessOverrideRule.java --- .../java/checks/sobriety/BrightnessOverrideRule.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/BrightnessOverrideRule.java b/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/BrightnessOverrideRule.java index 562464b5a..2b69a2e23 100644 --- a/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/BrightnessOverrideRule.java +++ b/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/BrightnessOverrideRule.java @@ -105,8 +105,10 @@ private boolean isBrightnessAssignment(AssignmentExpressionTree assignmentExpres } private void checkBrightnessAssignmentExpressionValue(Tree tree, String qualifiedType, Number value) { - if (qualifiedType.equals("float") && value.folatValue() == BRIGHTNESS_FULL_VALUE - || qualifiedType.equals("int") && value.intValue() == BRIGHTNESS_FULL_VALUE) { + int intValue = value.intValue(); + float floatValue = value.floatValue(); + if (qualifiedType.equals("float") && floatValue == BRIGHTNESS_FULL_VALUE + || qualifiedType.equals("int") && intValue == BRIGHTNESS_FULL_VALUE) { reportIssue(tree, ERROR_MESSAGE); } } From f84027cd3006ffd0b82272edcb20fd59ab9f6029 Mon Sep 17 00:00:00 2001 From: dedece35 Date: Tue, 8 Nov 2022 14:44:40 +0100 Subject: [PATCH 110/119] refactoring jdk version usage (move to parent pom.xml) --- src/android-plugin/pom.xml | 10 ---------- src/java-plugin/pom.xml | 12 ------------ src/php-plugin/pom.xml | 11 ----------- src/pom.xml | 28 ++++++++++++++++++++++------ src/python-plugin/pom.xml | 9 --------- src/xml-plugin/pom.xml | 11 ----------- 6 files changed, 22 insertions(+), 59 deletions(-) diff --git a/src/android-plugin/pom.xml b/src/android-plugin/pom.xml index 6d80f8645..62d2903c8 100644 --- a/src/android-plugin/pom.xml +++ b/src/android-plugin/pom.xml @@ -266,16 +266,6 @@ - - org.apache.maven.plugins - maven-compiler-plugin - 3.6.0 - - 11 - 11 - - - org.sonarsource.scanner.maven sonar-maven-plugin diff --git a/src/java-plugin/pom.xml b/src/java-plugin/pom.xml index 32a156b4c..a63ad3b67 100644 --- a/src/java-plugin/pom.xml +++ b/src/java-plugin/pom.xml @@ -8,7 +8,6 @@ 1.0.0-SNAPSHOT - ecocode-java-plugin sonar-plugin @@ -113,16 +112,6 @@ - - org.apache.maven.plugins - maven-compiler-plugin - 3.8.0 - - 11 - 11 - - - org.jacoco jacoco-maven-plugin @@ -213,5 +202,4 @@ - \ No newline at end of file diff --git a/src/php-plugin/pom.xml b/src/php-plugin/pom.xml index d595e0a25..55c0832c6 100644 --- a/src/php-plugin/pom.xml +++ b/src/php-plugin/pom.xml @@ -13,7 +13,6 @@ ecoCode PHP Sonar Plugin - org.sonarsource.sonarqube @@ -73,16 +72,6 @@ - - - org.apache.maven.plugins - maven-compiler-plugin - 3.6.0 - - 11 - 11 - - org.jacoco jacoco-maven-plugin diff --git a/src/pom.xml b/src/pom.xml index d8a9491aa..7cf401cd8 100644 --- a/src/pom.xml +++ b/src/pom.xml @@ -32,7 +32,6 @@ python-plugin codenarc-converter android-plugin - @@ -58,6 +57,11 @@ + + 11 + ${java.version} + ${java.version} + 8.7.1.42226 6.14.0.25463 @@ -74,10 +78,8 @@ UTF-8 - 11 - 11 - cnumr-1 - https://sonarcloud.io + cnumr-1 + https://sonarcloud.io @@ -156,7 +158,6 @@ test - junit junit @@ -180,5 +181,20 @@ + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.10.1 + + ${java.version} + ${java.version} + + + + + diff --git a/src/python-plugin/pom.xml b/src/python-plugin/pom.xml index f02362783..ec5c6d2da 100644 --- a/src/python-plugin/pom.xml +++ b/src/python-plugin/pom.xml @@ -81,15 +81,6 @@ - - - maven-compiler-plugin - 3.7.0 - - 11 - 11 - - diff --git a/src/xml-plugin/pom.xml b/src/xml-plugin/pom.xml index e1e71dea7..6291a6410 100644 --- a/src/xml-plugin/pom.xml +++ b/src/xml-plugin/pom.xml @@ -12,7 +12,6 @@ ecoCode XML Sonar Plugin - org.sonarsource.sonarqube @@ -86,16 +85,6 @@ - - - org.apache.maven.plugins - maven-compiler-plugin - 3.6.0 - - 11 - 11 - - From 8565df0e6ac1bb08a3a3584f087425335fd0f2b6 Mon Sep 17 00:00:00 2001 From: dedece35 Date: Tue, 8 Nov 2022 14:59:51 +0100 Subject: [PATCH 111/119] =?UTF-8?q?refactoring=20jdk=20version=20usage=20(?= =?UTF-8?q?move=20to=20parent=20pom.xml)=20-=20retour=20arri=C3=A8re=20and?= =?UTF-8?q?roid-plugin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/android-plugin/pom.xml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/android-plugin/pom.xml b/src/android-plugin/pom.xml index 62d2903c8..6d80f8645 100644 --- a/src/android-plugin/pom.xml +++ b/src/android-plugin/pom.xml @@ -266,6 +266,16 @@ + + org.apache.maven.plugins + maven-compiler-plugin + 3.6.0 + + 11 + 11 + + + org.sonarsource.scanner.maven sonar-maven-plugin From f486469c7cb2eed5b5bd501c0c60d8bdb1f42679 Mon Sep 17 00:00:00 2001 From: Mimi-a24 <53166454+Mimi-a24@users.noreply.github.com> Date: Tue, 8 Nov 2022 18:38:25 +0400 Subject: [PATCH 112/119] add rule: avoid multiple if else statement (#168) * add rule: avoid multiple if else statement * add description rule AMIES (Avoid Multiple If Else Statement * Fix sonar code smell & bug * Fix sonar code smell Co-authored-by: oussamaLaribi <63214114+oussamaLaribi@users.noreply.github.com> --- .../main/java/fr/cnumr/java/RulesList.java | 3 +- .../checks/AvoidMultipleIfElseStatement.java | 68 +++++++++++++++++++ .../fr/cnumr/l10n/java/rules/java/AMIES.html | 31 +++++++++ .../fr/cnumr/l10n/java/rules/java/AMIES.json | 13 ++++ .../files/AvoidMultipleIfElseStatement.java | 38 +++++++++++ .../AvoidMultipleIfElseStatementNoIssue.java | 31 +++++++++ .../java/MyJavaFileCheckRegistrarTest.java | 2 +- .../AvoidMultipleIfElseStatementTest.java | 20 ++++++ 8 files changed, 204 insertions(+), 2 deletions(-) create mode 100644 src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidMultipleIfElseStatement.java create mode 100644 src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/AMIES.html create mode 100644 src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/AMIES.json create mode 100644 src/java-plugin/src/test/files/AvoidMultipleIfElseStatement.java create mode 100644 src/java-plugin/src/test/files/AvoidMultipleIfElseStatementNoIssue.java create mode 100644 src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidMultipleIfElseStatementTest.java diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java b/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java index 160ce1b37..f4ca41a00 100644 --- a/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java +++ b/src/java-plugin/src/main/java/fr/cnumr/java/RulesList.java @@ -58,7 +58,8 @@ public static List> getJavaChecks() { InitializeBufferWithAppropriateSize.class, AvoidUsingGlobalVariablesCheck.class, AvoidSetConstantInBatchUpdate.class, - FreeResourcesOfAutoCloseableInterface.class + FreeResourcesOfAutoCloseableInterface.class, + AvoidMultipleIfElseStatement.class )); } diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidMultipleIfElseStatement.java b/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidMultipleIfElseStatement.java new file mode 100644 index 000000000..f40e420ce --- /dev/null +++ b/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidMultipleIfElseStatement.java @@ -0,0 +1,68 @@ +package fr.cnumr.java.checks; +import org.sonar.check.Priority; +import org.sonar.check.Rule; +import org.sonar.java.model.statement.BlockTreeImpl; +import org.sonar.java.model.statement.IfStatementTreeImpl; +import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; +import org.sonar.plugins.java.api.tree.StatementTree; +import org.sonar.plugins.java.api.tree.Tree; + +import java.util.Arrays; +import java.util.List; + +@Rule(key = "AMIES", + name = "Developpement", + description = AvoidMultipleIfElseStatement.RULE_MESSAGE, + priority = Priority.MINOR, + tags = {"bug" }) +public class AvoidMultipleIfElseStatement extends IssuableSubscriptionVisitor { + protected static final String RULE_MESSAGE = "Using a switch statement instead of multiple if-else if possible"; + + private void checkIfStatement(Tree tree) { + int sizeBody = 0; + int idx = 0; + int countIfStatement = 0; + + Tree parentNode = tree.parent(); + + if (!(parentNode instanceof BlockTreeImpl)) + return; + BlockTreeImpl node = (BlockTreeImpl) parentNode; + sizeBody = node.body().toArray().length; + while(idx < sizeBody) { + if (node.body().get(idx) instanceof IfStatementTreeImpl) + ++countIfStatement; + ++idx; + } + if (countIfStatement > 1) + reportIssue(tree, "using a switch statement instead of multiple if-else conditions (more than one)"); + } + + private void checkElseIfStatement(Tree tree) { + IfStatementTreeImpl node = (IfStatementTreeImpl) tree; + int count = 0; + StatementTree statementTree; + + while (true) { + if (count >= 2) + reportIssue(tree, "using a switch statement instead of multiple if-else if possible"); + statementTree = node.elseStatement(); + if (statementTree instanceof IfStatementTreeImpl) { + ++count; + node = (IfStatementTreeImpl) statementTree; + } else if (statementTree instanceof BlockTreeImpl) { + break; + } + } + } + + @Override + public List nodesToVisit() { + return Arrays.asList(Tree.Kind.IF_STATEMENT); + } + @Override + public void visitNode(Tree tree) { + checkIfStatement(tree); + checkElseIfStatement(tree); + } +} diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/AMIES.html b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/AMIES.html new file mode 100644 index 000000000..7e5fcc2a0 --- /dev/null +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/AMIES.html @@ -0,0 +1,31 @@ +

If we are using too many conditional if-else statements it will impact performance since JVM will have to compare the conditions. We can think of using a switch statement instead of multiple if-else if possible. Switch statement has a performance advantage over if – else.

+ +

Non-compliant Code Example

+
+		int index = 1;
+        int nb = 2;
+
+        if (nb > index) {
+            nb = nb + index;
+        } else {
+            nb = nb - 1;
+        }
+        if (nb != index + 1) {
+            nb = nb + index;
+        } else {
+            nb = nb - 1;
+        }
+
+
+
+

Compliant Code Example

+
+        int index = 1;
+        int nb = 2;
+
+        if (nb > index) {
+            nb = nb + index;
+        } else {
+            nb = nb - 1;
+        }
+
diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/AMIES.json b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/AMIES.json new file mode 100644 index 000000000..859f8bf3f --- /dev/null +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/AMIES.json @@ -0,0 +1,13 @@ +{ + "title": "Avoid multiple if-else statement", + "type": "CODE_SMELL", + "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "5min" + }, + "tags": [ + "eco-conception" + ], + "defaultSeverity": "Minor" +} \ No newline at end of file diff --git a/src/java-plugin/src/test/files/AvoidMultipleIfElseStatement.java b/src/java-plugin/src/test/files/AvoidMultipleIfElseStatement.java new file mode 100644 index 000000000..6b06cf825 --- /dev/null +++ b/src/java-plugin/src/test/files/AvoidMultipleIfElseStatement.java @@ -0,0 +1,38 @@ +package fr.cnumr.java.checks; + +class AvoidMultipleIfElseStatementCheck { + AvoidMultipleIfElseStatementCheck (AvoidMultipleIfElseStatementCheck mc) { + } + + public void methodWithMultipleIfElseIf() { + int nb1 = 0; + int nb2 = 10; + + if (nb1 == 1) { // Noncompliant + nb1 = 1; + } else if (nb1 == nb2) { + // + } else if (nb2 == nb1) { + // + } else { + // + } + nb1 = nb2; + } + + public void methodWithMultipleIfElse() { + int nb1 = 0; + int nb2 = 10; + + if (nb1 == 1) { // Noncompliant + nb1 = 1; + } else { + // + } + if (nb1 == 1) { // Noncompliant + nb1 = 1; + } else { + // + } + } +} \ No newline at end of file diff --git a/src/java-plugin/src/test/files/AvoidMultipleIfElseStatementNoIssue.java b/src/java-plugin/src/test/files/AvoidMultipleIfElseStatementNoIssue.java new file mode 100644 index 000000000..89c2de6d3 --- /dev/null +++ b/src/java-plugin/src/test/files/AvoidMultipleIfElseStatementNoIssue.java @@ -0,0 +1,31 @@ +package fr.cnumr.java.checks; + +class AvoidMultipleIfElseStatementNoIssueCheck { + AvoidMultipleIfElseStatementNoIssueCheck (AvoidMultipleIfElseStatementNoIssueCheck mc) { + } + + public void methodWithOneIfElseIf() { + int nb1 = 0; + int nb2 = 10; + + if (nb1 == 1) { + nb1 = 1; + } else if (nb1 == nb2) { + // + } else { + // + } + nb1 = nb2; + } + + public void methodWithOneIfElse() { + int nb1 = 0; + int nb2 = 10; + + if (nb1 == 1) { + nb1 = 1; + } else { + // + } + } +} \ No newline at end of file diff --git a/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java b/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java index fb368adee..2baa3fac9 100644 --- a/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java +++ b/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaFileCheckRegistrarTest.java @@ -34,7 +34,7 @@ void checkNumberRules() { final MyJavaFileCheckRegistrar registrar = new MyJavaFileCheckRegistrar(); registrar.register(context); - assertThat(context.checkClasses()).hasSize(18); + assertThat(context.checkClasses()).hasSize(19); assertThat(context.testCheckClasses()).isEmpty(); } } diff --git a/src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidMultipleIfElseStatementTest.java b/src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidMultipleIfElseStatementTest.java new file mode 100644 index 000000000..99227ffc4 --- /dev/null +++ b/src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidMultipleIfElseStatementTest.java @@ -0,0 +1,20 @@ +package fr.cnumr.java.checks; + +import org.junit.jupiter.api.Test; +import org.sonar.java.checks.verifier.CheckVerifier; + +class AvoidMultipleIfElseStatementTest { + @Test + void test() { + CheckVerifier.newVerifier() + .onFile("src/test/files/AvoidMultipleIfElseStatement.java") + .withCheck(new AvoidMultipleIfElseStatement()) + .verifyIssues(); + CheckVerifier.newVerifier() + .onFile("src/test/files/AvoidMultipleIfElseStatementNoIssue.java") + .withCheck(new AvoidMultipleIfElseStatement()) + .verifyNoIssues(); + } + + +} From b4d0e58e46d65300df9e68dd3317b632c492d909 Mon Sep 17 00:00:00 2001 From: MP-Aubay Date: Thu, 10 Nov 2022 14:19:03 +0100 Subject: [PATCH 113/119] Fix some Sonar Bugs and code smell (#141) * fix sonar issues and clean up * feat - Taking review in account --- .gitignore | 2 +- README.md | 2 +- src/.gitignore | 1 + .../java/checks/batch/JobCoalesceRule.java | 18 +-- .../java/checks/batch/SensorCoalesceRule.java | 17 +-- .../UncompressedDataTransmissionRule.java | 28 ++-- ...ava => CheckArgumentComplexTypeUtils.java} | 5 +- .../helpers/ConstructorBeforeMethodCheck.java | 2 +- .../java/checks/helpers/TreeHelper.java | 123 +++++++++++++----- .../constant/ArgumentValueOnMethodCheck.java | 4 +- .../checks/idleness/KeepVoiceAwakeRule.java | 20 ++- .../checks/power/ChargeAwarenessRule.java | 37 ++++-- .../checks/power/SaveModeAwarenessRule.java | 36 ++--- .../checks/sobriety/HighFrameRateRule.java | 4 +- .../ThriftyGeolocationCriteriaRule.java | 43 +++--- .../ThriftyGeolocationMinDistanceRule.java | 32 +++-- .../ThriftyGeolocationMinTimeRule.java | 32 +++-- .../checks/sobriety/VibrationFreeRule.java | 10 +- .../checks/helpers/CheckPermissionsRule.java | 2 +- .../checks/power/ChargeAwarenessXmlRule.java | 3 +- .../ecocode/java/JavaEcoCodeProfileTest.java | 2 +- .../io/ecocode/xml/XmlEcoCodeProfileTest.java | 2 +- .../java/checks/AvoidSQLRequestInLoop.java | 58 ++++----- .../fr/cnumr/java/checks/IncrementCheck.java | 1 - .../NoFunctionCallWhenDeclaringForLoop.java | 122 ++++++++--------- .../UnnecessarilyAssignValuesToVariables.java | 6 +- .../cnumr/java/MyJavaRulesDefinitionTest.java | 1 - ...idSpringRepositoryCallInLoopCheckTest.java | 2 +- ...oFunctionCallWhenDeclaringForLoopTest.java | 2 +- .../php/checks/AvoidDoubleQuoteCheck.java | 5 +- .../php/checks/AvoidFullSQLRequestCheck.java | 4 +- .../checks/AvoidSQLRequestInLoopCheck.java | 101 +++++++------- .../NoFunctionCallWhenDeclaringForLoop.java | 4 +- .../python/checks/AvoidFullSQLRequest.java | 9 +- .../AvoidGlobalVariableInFunctionCheck.java | 63 +++++++-- .../checks/AvoidTryCatchFinallyCheck.java | 2 - .../NoFunctionCallWhenDeclaringForLoop.java | 4 - 37 files changed, 453 insertions(+), 356 deletions(-) rename src/android-plugin/src/main/java/io/ecocode/java/checks/helpers/{CheckArgumentComplexType.java => CheckArgumentComplexTypeUtils.java} (95%) diff --git a/.gitignore b/.gitignore index 4572288da..7513da233 100644 --- a/.gitignore +++ b/.gitignore @@ -26,4 +26,4 @@ buildNumber.properties .settings/ # IntelliJ IDEA settings -.idea/ \ No newline at end of file +.idea \ No newline at end of file diff --git a/README.md b/README.md index 5a954c133..766e86078 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ --- -*ecoCode* is a collective project aiming at the reduction the environmental footprint of software at the code level. The goal of the project is to provide a list of static code analyzers to highlight code structures that may have a negative ecological impact: energy and resources over-consumption, "fatware", shortening terminals' lifespan, etc. +*ecoCode* is a collective project aiming to reduce environmental footprint of software at the code level. The goal of the project is to provide a list of static code analyzers to highlight code structures that may have a negative ecological impact: energy and resources over-consumption, "fatware", shortening terminals' lifespan, etc. ecoCode is based on evolving catalogs of [good practices](docs/rules), for various technologies. A SonarQube plugin then implement these catalogs as rules for scanning your projects. diff --git a/src/.gitignore b/src/.gitignore index f7a6afc7f..52789d918 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -6,3 +6,4 @@ target/ node/ *.iml /lib/*.jar +bin \ No newline at end of file diff --git a/src/android-plugin/src/main/java/io/ecocode/java/checks/batch/JobCoalesceRule.java b/src/android-plugin/src/main/java/io/ecocode/java/checks/batch/JobCoalesceRule.java index 7e9aae3e7..553135ccb 100644 --- a/src/android-plugin/src/main/java/io/ecocode/java/checks/batch/JobCoalesceRule.java +++ b/src/android-plugin/src/main/java/io/ecocode/java/checks/batch/JobCoalesceRule.java @@ -35,16 +35,18 @@ */ @Rule(key = "EBAT003", name = "ecocodeJobCoalesce") public class JobCoalesceRule extends IssuableSubscriptionVisitor { + + private static final String ALARM_MANAGER_CLASS = "android.app.AlarmManager"; private final MethodMatchers alarmSchedulerMethodMatcher = MethodMatchers.or( - MethodMatchers.create().ofTypes("android.app.AlarmManager").names("set").withAnyParameters().build(), - MethodMatchers.create().ofTypes("android.app.AlarmManager").names("setAlarmClock").withAnyParameters().build(), - MethodMatchers.create().ofTypes("android.app.AlarmManager").names("setAndAllowWhileIdle").withAnyParameters().build(), - MethodMatchers.create().ofTypes("android.app.AlarmManager").names("setExact").withAnyParameters().build(), - MethodMatchers.create().ofTypes("android.app.AlarmManager").names("setExactAndAllowWhileIdle").withAnyParameters().build(), - MethodMatchers.create().ofTypes("android.app.AlarmManager").names("setInexactRepeating").withAnyParameters().build(), - MethodMatchers.create().ofTypes("android.app.AlarmManager").names("setRepeating").withAnyParameters().build(), - MethodMatchers.create().ofTypes("android.app.AlarmManager").names("setWindow").withAnyParameters().build(), + MethodMatchers.create().ofTypes(ALARM_MANAGER_CLASS).names("set").withAnyParameters().build(), + MethodMatchers.create().ofTypes(ALARM_MANAGER_CLASS).names("setAlarmClock").withAnyParameters().build(), + MethodMatchers.create().ofTypes(ALARM_MANAGER_CLASS).names("setAndAllowWhileIdle").withAnyParameters().build(), + MethodMatchers.create().ofTypes(ALARM_MANAGER_CLASS).names("setExact").withAnyParameters().build(), + MethodMatchers.create().ofTypes(ALARM_MANAGER_CLASS).names("setExactAndAllowWhileIdle").withAnyParameters().build(), + MethodMatchers.create().ofTypes(ALARM_MANAGER_CLASS).names("setInexactRepeating").withAnyParameters().build(), + MethodMatchers.create().ofTypes(ALARM_MANAGER_CLASS).names("setRepeating").withAnyParameters().build(), + MethodMatchers.create().ofTypes(ALARM_MANAGER_CLASS).names("setWindow").withAnyParameters().build(), //ofAnyType is used because the method is forced to be overridden in a new class expending the abstract class AbstractThreadedSyncAdapter MethodMatchers.create().ofAnyType().names("onPerformSync").withAnyParameters().build(), //ofSubTypes is used because the method is from an abstract class diff --git a/src/android-plugin/src/main/java/io/ecocode/java/checks/batch/SensorCoalesceRule.java b/src/android-plugin/src/main/java/io/ecocode/java/checks/batch/SensorCoalesceRule.java index 5d9777fa3..090586391 100644 --- a/src/android-plugin/src/main/java/io/ecocode/java/checks/batch/SensorCoalesceRule.java +++ b/src/android-plugin/src/main/java/io/ecocode/java/checks/batch/SensorCoalesceRule.java @@ -20,7 +20,7 @@ package io.ecocode.java.checks.batch; import com.google.common.collect.ImmutableList; -import io.ecocode.java.checks.helpers.CheckArgumentComplexType; +import io.ecocode.java.checks.helpers.CheckArgumentComplexTypeUtils; import org.sonar.check.Rule; import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; import org.sonar.plugins.java.api.semantic.MethodMatchers; @@ -30,6 +30,7 @@ import org.sonar.plugins.java.api.tree.Tree; import java.util.List; +import java.util.Optional; /** * Check the call of the method "registerListener" of "android.hardware.SensorManager" with 4 parameters (the 4th one being the latency). @@ -53,10 +54,9 @@ public List nodesToVisit() { public void visitNode(Tree tree) { if (tree.is(Tree.Kind.METHOD_INVOCATION)) { MethodInvocationTree mit = (MethodInvocationTree) tree; - if (sensorListenerMethodMatcher.matches(mit)) { - if (!isFourthArgumentPositiveNumber(mit.arguments())) { - reportIssue(mit, "Prefer using a reported latency on your SensorManager to reduce the power consumption of the app"); - } + if (sensorListenerMethodMatcher.matches(mit) + && !isFourthArgumentPositiveNumber(mit.arguments())) { + reportIssue(mit, "Prefer using a reported latency on your SensorManager to reduce the power consumption of the app"); } } } @@ -74,13 +74,14 @@ private boolean isFourthArgumentPositiveNumber(Arguments arguments) { ExpressionTree thirdArgument = arguments.get(3); //Check 4th argument is a complex type (that needs to be managed) while (thirdArgument.is(Tree.Kind.TYPE_CAST, Tree.Kind.MEMBER_SELECT, Tree.Kind.PARENTHESIZED_EXPRESSION)) { - thirdArgument = (ExpressionTree) CheckArgumentComplexType.getChildExpression(thirdArgument); + thirdArgument = (ExpressionTree) CheckArgumentComplexTypeUtils.getChildExpression(thirdArgument); } - return thirdArgument.asConstant().isPresent() + Optional optionalThirdArgument = thirdArgument.asConstant(); + return optionalThirdArgument.isPresent() //Check 4th argument is a number && (thirdArgument.is(Tree.Kind.INT_LITERAL, Tree.Kind.LONG_LITERAL, Tree.Kind.FLOAT_LITERAL, Tree.Kind.DOUBLE_LITERAL) //Check 4th argument is strictly positive - && ((Number) thirdArgument.asConstant().get()).doubleValue() > 0); + && ((Number) optionalThirdArgument.get()).doubleValue() > 0); } return false; } diff --git a/src/android-plugin/src/main/java/io/ecocode/java/checks/bottleneck/UncompressedDataTransmissionRule.java b/src/android-plugin/src/main/java/io/ecocode/java/checks/bottleneck/UncompressedDataTransmissionRule.java index 2e72f45a5..0b7b65bd6 100644 --- a/src/android-plugin/src/main/java/io/ecocode/java/checks/bottleneck/UncompressedDataTransmissionRule.java +++ b/src/android-plugin/src/main/java/io/ecocode/java/checks/bottleneck/UncompressedDataTransmissionRule.java @@ -19,14 +19,24 @@ */ package io.ecocode.java.checks.bottleneck; -import com.google.common.collect.ImmutableList; -import io.ecocode.java.checks.helpers.CheckArgumentComplexType; +import java.util.List; + +import org.sonar.api.utils.log.Logger; +import org.sonar.api.utils.log.Loggers; import org.sonar.check.Rule; import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; import org.sonar.plugins.java.api.semantic.MethodMatchers; -import org.sonar.plugins.java.api.tree.*; +import org.sonar.plugins.java.api.tree.Arguments; +import org.sonar.plugins.java.api.tree.ExpressionTree; +import org.sonar.plugins.java.api.tree.IdentifierTree; +import org.sonar.plugins.java.api.tree.MethodInvocationTree; +import org.sonar.plugins.java.api.tree.NewClassTree; +import org.sonar.plugins.java.api.tree.Tree; +import org.sonar.plugins.java.api.tree.VariableTree; -import java.util.List; +import com.google.common.collect.ImmutableList; + +import io.ecocode.java.checks.helpers.CheckArgumentComplexTypeUtils; /** * If an OutputStream class is created: @@ -35,6 +45,8 @@ */ @Rule(key = "EBOT003", name = "ecoCodeUncompressedDataTransmission") public class UncompressedDataTransmissionRule extends IssuableSubscriptionVisitor { + private static final Logger LOG = Loggers.get(UncompressedDataTransmissionRule.class); + private static final String ERROR_MESSAGE = "Prefer using GzipOutputStream instead of OutputStream to improve energy efficiency."; private static final MethodMatchers matcherUrlConnection = MethodMatchers.create().ofSubTypes("java.net.URLConnection").names("getOutputStream").addWithoutParametersMatcher().build(); // TODO: 22/03/2022 Change methodMatcher for anything but a "new GZIPOutputStream()", the new being the problem here. @@ -75,22 +87,22 @@ private void checkMethodInitilization(Tree treeToCheck, Tree treeToReport) { } else if (treeToCheck.is(Tree.Kind.NEW_CLASS)) { Arguments argumentsTreeToCheck = ((NewClassTree) treeToCheck).arguments(); List identifierTreeToCheck = ((NewClassTree) treeToCheck).constructorSymbol().usages(); - if (argumentsTreeToCheck.size() != 0 - && identifierTreeToCheck.size() != 0 + if (!argumentsTreeToCheck.isEmpty() + && !identifierTreeToCheck.isEmpty() && argumentsTreeToCheck.get(0).is(Tree.Kind.METHOD_INVOCATION) && ((MethodInvocationTree) argumentsTreeToCheck.get(0)).symbol().name().contains("getOutputStream") && !(identifierTreeToCheck.get(0).name().equals("GZIPOutputStream"))) { reportIssue(treeToReport, ERROR_MESSAGE); } } else { - Tree returnedArgument = (Tree) CheckArgumentComplexType.getChildExpression((ExpressionTree) treeToCheck); + Tree returnedArgument = (Tree) CheckArgumentComplexTypeUtils.getChildExpression((ExpressionTree) treeToCheck); if (returnedArgument != treeToCheck) { checkMethodInitilization(returnedArgument, treeToReport); } } } catch (Exception e) { - e.printStackTrace(); + LOG.error("Error in checkMethodInitilization : {}", e.getMessage(), e); } } } \ No newline at end of file diff --git a/src/android-plugin/src/main/java/io/ecocode/java/checks/helpers/CheckArgumentComplexType.java b/src/android-plugin/src/main/java/io/ecocode/java/checks/helpers/CheckArgumentComplexTypeUtils.java similarity index 95% rename from src/android-plugin/src/main/java/io/ecocode/java/checks/helpers/CheckArgumentComplexType.java rename to src/android-plugin/src/main/java/io/ecocode/java/checks/helpers/CheckArgumentComplexTypeUtils.java index 1c3baa56b..0b0f1fa88 100644 --- a/src/android-plugin/src/main/java/io/ecocode/java/checks/helpers/CheckArgumentComplexType.java +++ b/src/android-plugin/src/main/java/io/ecocode/java/checks/helpers/CheckArgumentComplexTypeUtils.java @@ -24,7 +24,10 @@ import org.sonar.plugins.java.api.tree.ParenthesizedTree; import org.sonar.plugins.java.api.tree.TypeCastTree; -public class CheckArgumentComplexType { +public class CheckArgumentComplexTypeUtils { + + private CheckArgumentComplexTypeUtils() { + } /** * Method that gives the argument's child value when it's of a complex type diff --git a/src/android-plugin/src/main/java/io/ecocode/java/checks/helpers/ConstructorBeforeMethodCheck.java b/src/android-plugin/src/main/java/io/ecocode/java/checks/helpers/ConstructorBeforeMethodCheck.java index da7d17b78..debf00439 100644 --- a/src/android-plugin/src/main/java/io/ecocode/java/checks/helpers/ConstructorBeforeMethodCheck.java +++ b/src/android-plugin/src/main/java/io/ecocode/java/checks/helpers/ConstructorBeforeMethodCheck.java @@ -51,7 +51,7 @@ public abstract class ConstructorBeforeMethodCheck extends IssuableSubscriptionV */ public abstract String getMessage(); - public ConstructorBeforeMethodCheck(String ownerType, String methodName) { + protected ConstructorBeforeMethodCheck(String ownerType, String methodName) { this.ownerType = ownerType; hasSeenMethod = false; this.releaseMatcher = MethodMatchers.create().ofTypes(ownerType).names(methodName).withAnyParameters().build(); diff --git a/src/android-plugin/src/main/java/io/ecocode/java/checks/helpers/TreeHelper.java b/src/android-plugin/src/main/java/io/ecocode/java/checks/helpers/TreeHelper.java index 2a7ade76e..471959533 100644 --- a/src/android-plugin/src/main/java/io/ecocode/java/checks/helpers/TreeHelper.java +++ b/src/android-plugin/src/main/java/io/ecocode/java/checks/helpers/TreeHelper.java @@ -19,9 +19,14 @@ */ package io.ecocode.java.checks.helpers; -import org.sonar.plugins.java.api.tree.*; +import java.util.List; +import java.util.Optional; -import java.util.ArrayList; +import org.sonar.plugins.java.api.tree.ExpressionTree; +import org.sonar.plugins.java.api.tree.IdentifierTree; +import org.sonar.plugins.java.api.tree.LiteralTree; +import org.sonar.plugins.java.api.tree.MemberSelectExpressionTree; +import org.sonar.plugins.java.api.tree.Tree; public class TreeHelper { @@ -52,48 +57,20 @@ public static String fullQualifiedName(Tree tree) { * @param treesToReport the tree to report the issue * @param valueToControl the value for which we report an issue if the argument is equal to the value */ - public static void literalValueControl(ExpressionTree argument, ArrayList treesToReport, int valueToControl) { + public static void literalValueControl(ExpressionTree argument, List treesToReport, int valueToControl) { try { switch (argument.symbolType().fullyQualifiedName()) { case "int": - if (argument.asConstant().isPresent() && ((Integer) argument.asConstant().get() == valueToControl)) { - treesToReport.add(argument); - } else if (argument.is(Tree.Kind.INT_LITERAL)) { - LiteralTree lit = (LiteralTree) argument; - if (Integer.valueOf(lit.value()) == valueToControl) { - treesToReport.add(argument); - } - } + literalValueControlForInt(argument, treesToReport, valueToControl); break; case "float": - if (argument.asConstant().isPresent() && ((Float) argument.asConstant().get() == valueToControl)) { - treesToReport.add(argument); - } else if (argument.is(Tree.Kind.FLOAT_LITERAL)) { - LiteralTree lit = (LiteralTree) argument; - if (Float.valueOf(lit.value()) == valueToControl) { - treesToReport.add(argument); - } - } + literalValueControlForFloat(argument, treesToReport, valueToControl); break; case "double": - if (argument.asConstant().isPresent() && ((Double) argument.asConstant().get() == valueToControl)) { - treesToReport.add(argument); - } else if (argument.is(Tree.Kind.DOUBLE_LITERAL)) { - LiteralTree lit = (LiteralTree) argument; - if (Double.valueOf(lit.value()) == valueToControl) { - treesToReport.add(argument); - } - } + literalValueControlForDouble(argument, treesToReport, valueToControl); break; case "long": - if (argument.asConstant().isPresent() && ((Long) argument.asConstant().get() == valueToControl)) { - treesToReport.add(argument); - } else if (argument.is(Tree.Kind.LONG_LITERAL)) { - LiteralTree lit = (LiteralTree) argument; - if (Long.valueOf(lit.value()) == valueToControl) { - treesToReport.add(argument); - } - } + literalValueControlForLong(argument, treesToReport, valueToControl); break; default: break; @@ -104,4 +81,80 @@ public static void literalValueControl(ExpressionTree argument, ArrayList // will always succeed } } + + /** + * Check if the value of the given expression is equal to a given value when it is an int. + * + * @param argument the argument to check + * @param treesToReport the tree to report the issue + * @param valueToControl the value for which we report an issue if the argument is equal to the value + */ + public static void literalValueControlForInt(ExpressionTree argument, List treesToReport, int valueToControl) { + Optional optionalArgument = argument.asConstant(); + if (optionalArgument.isPresent() && ((Integer) optionalArgument.get() == valueToControl)) { + treesToReport.add(argument); + } else if (argument.is(Tree.Kind.INT_LITERAL)) { + LiteralTree lit = (LiteralTree) argument; + if (Integer.valueOf(lit.value()) == valueToControl) { + treesToReport.add(argument); + } + } + } + + /** + * Check if the value of the given expression is equal to a given value when it is an float. + * + * @param argument the argument to check + * @param treesToReport the tree to report the issue + * @param valueToControl the value for which we report an issue if the argument is equal to the value + */ + public static void literalValueControlForFloat(ExpressionTree argument, List treesToReport, int valueToControl) { + Optional optionalArgument = argument.asConstant(); + if (optionalArgument.isPresent() && ((Float) optionalArgument.get() == valueToControl)) { + treesToReport.add(argument); + } else if (argument.is(Tree.Kind.FLOAT_LITERAL)) { + LiteralTree lit = (LiteralTree) argument; + if (Float.valueOf(lit.value()) == valueToControl) { + treesToReport.add(argument); + } + } + } + + /** + * Check if the value of the given expression is equal to a given value when it is an double. + * + * @param argument the argument to check + * @param treesToReport the tree to report the issue + * @param valueToControl the value for which we report an issue if the argument is equal to the value + */ + public static void literalValueControlForDouble(ExpressionTree argument, List treesToReport, int valueToControl) { + Optional optionalArgument = argument.asConstant(); + if (optionalArgument.isPresent() && ((Double) optionalArgument.get() == valueToControl)) { + treesToReport.add(argument); + } else if (argument.is(Tree.Kind.DOUBLE_LITERAL)) { + LiteralTree lit = (LiteralTree) argument; + if (Double.valueOf(lit.value()) == valueToControl) { + treesToReport.add(argument); + } + } + } + + /** + * Check if the value of the given expression is equal to a given value when it is an long. + * + * @param argument the argument to check + * @param treesToReport the tree to report the issue + * @param valueToControl the value for which we report an issue if the argument is equal to the value + */ + public static void literalValueControlForLong(ExpressionTree argument, List treesToReport, int valueToControl) { + Optional optionalArgument = argument.asConstant(); + if (optionalArgument.isPresent() && ((Long) optionalArgument.get() == valueToControl)) { + treesToReport.add(argument); + } else if (argument.is(Tree.Kind.LONG_LITERAL)) { + LiteralTree lit = (LiteralTree) argument; + if (Long.valueOf(lit.value()) == valueToControl) { + treesToReport.add(argument); + } + } + } } diff --git a/src/android-plugin/src/main/java/io/ecocode/java/checks/helpers/constant/ArgumentValueOnMethodCheck.java b/src/android-plugin/src/main/java/io/ecocode/java/checks/helpers/constant/ArgumentValueOnMethodCheck.java index 39ee0dc3f..65dbf820d 100644 --- a/src/android-plugin/src/main/java/io/ecocode/java/checks/helpers/constant/ArgumentValueOnMethodCheck.java +++ b/src/android-plugin/src/main/java/io/ecocode/java/checks/helpers/constant/ArgumentValueOnMethodCheck.java @@ -20,7 +20,7 @@ package io.ecocode.java.checks.helpers.constant; import com.google.common.collect.ImmutableList; -import io.ecocode.java.checks.helpers.CheckArgumentComplexType; +import io.ecocode.java.checks.helpers.CheckArgumentComplexTypeUtils; import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; import org.sonar.plugins.java.api.semantic.MethodMatchers; import org.sonar.plugins.java.api.tree.ExpressionTree; @@ -118,7 +118,7 @@ private void handleArgument(ExpressionTree argument) { || argument.is(Tree.Kind.BOOLEAN_LITERAL)) { checkConstantValue(argument.asConstant(), argument, constantValueToCheck); } else { - ExpressionTree returnedArgument = (ExpressionTree) CheckArgumentComplexType.getChildExpression(argument); + ExpressionTree returnedArgument = (ExpressionTree) CheckArgumentComplexTypeUtils.getChildExpression(argument); if (returnedArgument != argument) { handleArgument(returnedArgument); } diff --git a/src/android-plugin/src/main/java/io/ecocode/java/checks/idleness/KeepVoiceAwakeRule.java b/src/android-plugin/src/main/java/io/ecocode/java/checks/idleness/KeepVoiceAwakeRule.java index 7806302f9..79bdd4eb6 100644 --- a/src/android-plugin/src/main/java/io/ecocode/java/checks/idleness/KeepVoiceAwakeRule.java +++ b/src/android-plugin/src/main/java/io/ecocode/java/checks/idleness/KeepVoiceAwakeRule.java @@ -20,7 +20,7 @@ package io.ecocode.java.checks.idleness; import com.google.common.collect.ImmutableList; -import io.ecocode.java.checks.helpers.CheckArgumentComplexType; +import io.ecocode.java.checks.helpers.CheckArgumentComplexTypeUtils; import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Loggers; import org.sonar.check.Rule; @@ -46,10 +46,10 @@ public class KeepVoiceAwakeRule extends IssuableSubscriptionVisitor { private static final Logger LOG = Loggers.get(KeepVoiceAwakeRule.class); - private final String ownerType = "android.service.voice.VoiceInteractionSession"; - private final String methodName = "setKeepAwake"; + private static final String OWNER_TYPE = "android.service.voice.VoiceInteractionSession"; + private static final String METHOD_NAME = "setKeepAwake"; private static final String ERROR_MESSAGE = "VoiceInteractionSession.setKeepAwake(false) should be called to limit battery drain."; - private final MethodMatchers methodMatcher = MethodMatchers.create().ofTypes(ownerType).names(methodName).addParametersMatcher("boolean").build(); + private final MethodMatchers methodMatcher = MethodMatchers.create().ofTypes(OWNER_TYPE).names(METHOD_NAME).addParametersMatcher("boolean").build(); private boolean hasSeenMethod; private boolean hasSeenMethodTrue = false; private final List constructorTreeList = new ArrayList<>(); @@ -87,16 +87,14 @@ private void initializeRule() { public void visitNode(Tree tree) { if (tree.is(Tree.Kind.NEW_CLASS)) { NewClassTree newClasstree = (NewClassTree) tree; - if (newClasstree.symbolType().fullyQualifiedName().equals(ownerType)) { + if (newClasstree.symbolType().fullyQualifiedName().equals(OWNER_TYPE)) { constructorTreeList.add(tree); } } else if (tree.is(Tree.Kind.METHOD_INVOCATION)) { MethodInvocationTree mit = (MethodInvocationTree) tree; - if (!mit.arguments().isEmpty()) { - if (methodMatcher.matches(mit)) { - // Get first argument of VoiceInteractionSession.setKeepAwake(Boolean) - handleArgument(mit.arguments().get(0)); - } + if (!mit.arguments().isEmpty() && methodMatcher.matches(mit)) { + // Get first argument of VoiceInteractionSession.setKeepAwake(Boolean) + handleArgument(mit.arguments().get(0)); } } } @@ -126,7 +124,7 @@ private void handleArgument(ExpressionTree argument) { } else if (argument.is(Tree.Kind.BOOLEAN_LITERAL)) { checkArgumentIsTrue(argument, argument.asConstant()); } else { - ExpressionTree returnedArgument = (ExpressionTree) CheckArgumentComplexType.getChildExpression(argument); + ExpressionTree returnedArgument = (ExpressionTree) CheckArgumentComplexTypeUtils.getChildExpression(argument); if (returnedArgument != argument) { handleArgument(returnedArgument); } diff --git a/src/android-plugin/src/main/java/io/ecocode/java/checks/power/ChargeAwarenessRule.java b/src/android-plugin/src/main/java/io/ecocode/java/checks/power/ChargeAwarenessRule.java index 09eeb8083..39f350c91 100644 --- a/src/android-plugin/src/main/java/io/ecocode/java/checks/power/ChargeAwarenessRule.java +++ b/src/android-plugin/src/main/java/io/ecocode/java/checks/power/ChargeAwarenessRule.java @@ -19,13 +19,21 @@ */ package io.ecocode.java.checks.power; -import com.google.common.collect.ImmutableList; +import java.util.List; +import java.util.Optional; + +import org.sonar.api.utils.log.Logger; +import org.sonar.api.utils.log.Loggers; import org.sonar.check.Rule; import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; import org.sonar.plugins.java.api.semantic.MethodMatchers; -import org.sonar.plugins.java.api.tree.*; +import org.sonar.plugins.java.api.tree.Arguments; +import org.sonar.plugins.java.api.tree.ExpressionTree; +import org.sonar.plugins.java.api.tree.MethodInvocationTree; +import org.sonar.plugins.java.api.tree.NewClassTree; +import org.sonar.plugins.java.api.tree.Tree; -import java.util.List; +import com.google.common.collect.ImmutableList; /** * Look for `android.content.IntentFilter` constructor declaration or call to `IntentFilter.addAction()` or ` @@ -36,15 +44,17 @@ */ @Rule(key = "EPOW004", name = "ecocodeChargeAwareness") public class ChargeAwarenessRule extends IssuableSubscriptionVisitor { - + private static final Logger LOG = Loggers.get(ChargeAwarenessRule.class); + private static final String ACTION_POWER_DISCONNECTED = "android.intent.action.ACTION_POWER_DISCONNECTED"; private static final String ACTION_POWER_CONNECTED = "android.intent.action.ACTION_POWER_CONNECTED"; private static final String ACTION_POWER_BATTERY_LOW = "android.intent.action.BATTERY_LOW"; private static final String ACTION_POWER_BATTERY_OKAY = "android.intent.action.BATTERY_OKAY"; + private static final String INTENT_FILTER = "android.content.IntentFilter"; private static final String INFO_MESSAGE = "Monitoring power changes and customizing behavior depending on battery level is a good practice."; private final MethodMatchers addActionOrIntentFilterMatcher = MethodMatchers.or( - MethodMatchers.create().ofTypes("android.content.IntentFilter").names("addAction").withAnyParameters().build(), - MethodMatchers.create().ofTypes("android.content.IntentFilter").names("create").withAnyParameters().build()); + MethodMatchers.create().ofTypes(INTENT_FILTER).names("addAction").withAnyParameters().build(), + MethodMatchers.create().ofTypes(INTENT_FILTER).names("create").withAnyParameters().build()); @Override public List nodesToVisit() { @@ -57,7 +67,7 @@ public void visitNode(Tree tree) { try { if (tree.is(Tree.Kind.NEW_CLASS)) { NewClassTree nct = (NewClassTree) tree; - if (nct.symbolType().fullyQualifiedName().equals("android.content.IntentFilter")) { + if (nct.symbolType().fullyQualifiedName().equals(INTENT_FILTER)) { checkParameter(nct.arguments()); } } @@ -68,19 +78,20 @@ public void visitNode(Tree tree) { } } } catch (Exception e) { - e.printStackTrace(); + LOG.error("Error in visitNode : {}", e.getMessage(), e); } } private void checkParameter(Arguments arguments) { if (!arguments.isEmpty()) { ExpressionTree firstArgument = arguments.get(0); + Optional optionalFirstArgument = firstArgument.asConstant(); if (firstArgument.symbolType().toString().equals("String") - && firstArgument.asConstant().isPresent() - && ((firstArgument.asConstant().get()).equals(ACTION_POWER_CONNECTED) - || (firstArgument.asConstant().get()).equals(ACTION_POWER_DISCONNECTED) - || (firstArgument.asConstant().get()).equals(ACTION_POWER_BATTERY_OKAY) - || (firstArgument.asConstant().get()).equals(ACTION_POWER_BATTERY_LOW))) { + && optionalFirstArgument.isPresent() + && ((optionalFirstArgument.get()).equals(ACTION_POWER_CONNECTED) + || (optionalFirstArgument.get()).equals(ACTION_POWER_DISCONNECTED) + || (optionalFirstArgument.get()).equals(ACTION_POWER_BATTERY_OKAY) + || (optionalFirstArgument.get()).equals(ACTION_POWER_BATTERY_LOW))) { reportIssue(firstArgument, INFO_MESSAGE); } } diff --git a/src/android-plugin/src/main/java/io/ecocode/java/checks/power/SaveModeAwarenessRule.java b/src/android-plugin/src/main/java/io/ecocode/java/checks/power/SaveModeAwarenessRule.java index 410f03df5..a8f9db450 100644 --- a/src/android-plugin/src/main/java/io/ecocode/java/checks/power/SaveModeAwarenessRule.java +++ b/src/android-plugin/src/main/java/io/ecocode/java/checks/power/SaveModeAwarenessRule.java @@ -19,27 +19,32 @@ */ package io.ecocode.java.checks.power; -import com.google.common.collect.ImmutableList; +import java.util.List; +import java.util.Optional; + +import org.sonar.api.utils.log.Logger; +import org.sonar.api.utils.log.Loggers; import org.sonar.check.Rule; import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; import org.sonar.plugins.java.api.semantic.MethodMatchers; -import org.sonar.plugins.java.api.tree.ExpressionTree; import org.sonar.plugins.java.api.tree.MethodInvocationTree; import org.sonar.plugins.java.api.tree.NewClassTree; import org.sonar.plugins.java.api.tree.Tree; -import java.util.List; +import com.google.common.collect.ImmutableList; /** * Checks the use of the BATTERY_CHANGED propriety in intentFilter or the use of the isPowerSaveMode() method */ @Rule(key = "EPOW006", name = "ecocodeSaveModeAwareness") public class SaveModeAwarenessRule extends IssuableSubscriptionVisitor { - + private static final Logger LOG = Loggers.get(SaveModeAwarenessRule.class); + private static final String ACTION_BATTERY_CHANGED = "android.intent.action.BATTERY_CHANGED"; + private static final String INTENT_FILTER = "android.content.IntentFilter"; private static final String ADVICE_MESSAGE = "Taking into account when the device is entering or exiting the power save mode is a good practice."; - private final MethodMatchers addActionMatcher = MethodMatchers.create().ofTypes("android.content.IntentFilter").names("addAction").withAnyParameters().build(); - private final MethodMatchers createIntentFilterMatcher = MethodMatchers.create().ofTypes("android.content.IntentFilter").names("create").withAnyParameters().build(); + private final MethodMatchers addActionMatcher = MethodMatchers.create().ofTypes(INTENT_FILTER).names("addAction").withAnyParameters().build(); + private final MethodMatchers createIntentFilterMatcher = MethodMatchers.create().ofTypes(INTENT_FILTER).names("create").withAnyParameters().build(); private final MethodMatchers isPowerSaveModeMatcher = MethodMatchers.create().ofTypes("android.os.PowerManager").names("isPowerSaveMode").withAnyParameters().build(); @Override @@ -53,12 +58,14 @@ public void visitNode(Tree tree) { try { if (tree.is(Tree.Kind.NEW_CLASS)) { NewClassTree nct = (NewClassTree) tree; - if (nct.symbolType().fullyQualifiedName().equals("android.content.IntentFilter") - && !nct.arguments().isEmpty() - && nct.arguments().get(0).asConstant().isPresent() - && nct.arguments().get(0).symbolType().toString().equals("String") - && nct.arguments().get(0).asConstant().get().equals(ACTION_BATTERY_CHANGED)) { - reportIssue(nct.arguments().get(0), ADVICE_MESSAGE); + if (nct.symbolType().fullyQualifiedName().equals(INTENT_FILTER) + && !nct.arguments().isEmpty()) { + Optional optionalNct = nct.arguments().get(0).asConstant(); + if (optionalNct.isPresent() + && nct.arguments().get(0).symbolType().toString().equals("String") + && optionalNct.get().equals(ACTION_BATTERY_CHANGED)) { + reportIssue(nct.arguments().get(0), ADVICE_MESSAGE); + } } } if (tree.is(Tree.Kind.METHOD_INVOCATION)) { @@ -73,9 +80,8 @@ public void visitNode(Tree tree) { reportIssue(mit, ADVICE_MESSAGE); } } - } catch ( - Exception e) { - e.printStackTrace(); + } catch (Exception e) { + LOG.error("Error in visitNode : {}", e.getMessage(), e); } } } \ No newline at end of file diff --git a/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java b/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java index f4a12296d..8d9817db2 100644 --- a/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java +++ b/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/HighFrameRateRule.java @@ -1,7 +1,7 @@ package io.ecocode.java.checks.sobriety; import com.google.common.collect.ImmutableList; -import io.ecocode.java.checks.helpers.CheckArgumentComplexType; +import io.ecocode.java.checks.helpers.CheckArgumentComplexTypeUtils; import org.sonar.check.Rule; import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; import org.sonar.plugins.java.api.semantic.MethodMatchers; @@ -52,7 +52,7 @@ private boolean isRefreshSixtyOrHigher(Arguments arguments) { return ((Float) argValue).floatValue() > FRAME_RATE_60; } } else if (firstArg.is(Tree.Kind.FLOAT_LITERAL)) { - firstArg = (ExpressionTree) CheckArgumentComplexType.getChildExpression(firstArg); + firstArg = (ExpressionTree) CheckArgumentComplexTypeUtils.getChildExpression(firstArg); LiteralTree lit = (LiteralTree) firstArg; return Float.valueOf(lit.value()) > FRAME_RATE_60; } diff --git a/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/ThriftyGeolocationCriteriaRule.java b/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/ThriftyGeolocationCriteriaRule.java index 04e8f42e4..7044a37bd 100644 --- a/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/ThriftyGeolocationCriteriaRule.java +++ b/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/ThriftyGeolocationCriteriaRule.java @@ -19,7 +19,10 @@ */ package io.ecocode.java.checks.sobriety; -import com.google.common.collect.ImmutableList; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + import org.sonar.check.Rule; import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; import org.sonar.plugins.java.api.JavaFileScannerContext; @@ -28,8 +31,7 @@ import org.sonar.plugins.java.api.tree.MethodInvocationTree; import org.sonar.plugins.java.api.tree.Tree; -import java.util.ArrayList; -import java.util.List; +import com.google.common.collect.ImmutableList; /** * - Visit the method invocation nodes. @@ -50,6 +52,13 @@ @Rule(key = "ESOB006", name = "ecocodeThriftyGeolocationCriteriaRule") public class ThriftyGeolocationCriteriaRule extends IssuableSubscriptionVisitor { + // CASE 1 + private static final String REPORT_MESSAGE_REQUEST_LOCATION = "You should configure a location provider (LocationManager.getBestProvider(...)) to optimize battery usage."; + // CASE 2 + private static final String REPORT_MESSAGE_BEST_PROVIDER = "You should call Criteria.setPowerRequirement(POWER_LOW) to optimize battery usage."; + // CASE 3 + private static final String REPORT_MESSAGE_SET_POWER_REQUIREMENT = "You should set the power requirement to POWER_LOW to optimize battery usage."; + private final MethodMatchers matcherCriteria = MethodMatchers.create().ofTypes("android.location.Criteria").names("setPowerRequirement").withAnyParameters().build(); private final MethodMatchers matcherBestProvider = MethodMatchers.create().ofTypes("android.location.LocationManager").names("getBestProvider").withAnyParameters().build(); private final MethodMatchers matcherRequestLocation = MethodMatchers.create().ofTypes("android.location.LocationManager").names("requestLocationUpdates").withAnyParameters().build(); @@ -59,21 +68,6 @@ public class ThriftyGeolocationCriteriaRule extends IssuableSubscriptionVisitor private boolean hasSeenSetBestProvider = false; private boolean hasSeenSetPowerRequirement = false; - // CASE 1 - public String getReportMessageRequestLocation() { - return "You should configure a location provider (LocationManager.getBestProvider(...)) to optimize battery usage."; - } - - // CASE 2 - public String getReportMessageBestProvider() { - return "You should call Criteria.setPowerRequirement(POWER_LOW) to optimize battery usage."; - } - - // CASE 3 - public String getReportMessageSetPowerRequirement() { - return "You should set the power requirement to POWER_LOW to optimize battery usage."; - } - @Override public List nodesToVisit() { return ImmutableList.of(Tree.Kind.METHOD_INVOCATION); @@ -85,12 +79,12 @@ public void leaveFile(JavaFileScannerContext context) { && hasSeenRequestLocation) { if (!hasSeenSetBestProvider) { for (Tree tree : requestTreesToReport) { - reportIssue(tree, getReportMessageRequestLocation()); + reportIssue(tree, REPORT_MESSAGE_REQUEST_LOCATION); } } else { if (!hasSeenSetPowerRequirement) { for (Tree tree : bestProviderTreeToReport) { - reportIssue(tree, getReportMessageBestProvider()); + reportIssue(tree, REPORT_MESSAGE_BEST_PROVIDER); } } } @@ -119,17 +113,18 @@ public void visitNode(Tree tree) { hasSeenSetPowerRequirement = true; if (!mit.arguments().isEmpty()) { ExpressionTree arg = mit.arguments().get(0); + Optional optionalArg = arg.asConstant(); try { - if (arg.asConstant().isPresent() && ((Integer) arg.asConstant().get()) == 1) { + if (optionalArg.isPresent() && ((Integer) optionalArg.get()) == 1) { hasSeenSetPowerRequirement = true; } else { - reportIssue(mit, getReportMessageSetPowerRequirement()); + reportIssue(mit, REPORT_MESSAGE_SET_POWER_REQUIREMENT); } } catch (Exception e) { - reportIssue(mit, getReportMessageSetPowerRequirement()); + reportIssue(mit, REPORT_MESSAGE_SET_POWER_REQUIREMENT); } } else { - reportIssue(mit, getReportMessageSetPowerRequirement()); + reportIssue(mit, REPORT_MESSAGE_SET_POWER_REQUIREMENT); } } } diff --git a/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/ThriftyGeolocationMinDistanceRule.java b/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/ThriftyGeolocationMinDistanceRule.java index 6175c96c2..702694502 100644 --- a/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/ThriftyGeolocationMinDistanceRule.java +++ b/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/ThriftyGeolocationMinDistanceRule.java @@ -56,24 +56,22 @@ public List nodesToVisit() { public void visitNode(Tree tree) { if (tree.is(Tree.Kind.METHOD_INVOCATION)) { MethodInvocationTree mit = (MethodInvocationTree) tree; - if (methodMatcher.matches(mit)) { - if (!mit.arguments().isEmpty()) { - ExpressionTree firstArgument = mit.arguments().get(0); - /* - * Here we want to know if the first parameter is a String, - * if it is, the minDistance Parameter will be at position 2 - * else, the minDistance will be at position 1 - */ - try { - if (firstArgument.symbolType().toString().equals("String") || firstArgument.is(Tree.Kind.NULL_LITERAL)) { - TreeHelper.literalValueControl(mit.arguments().get(2), treesToReport, ARGUMENT_VALUE_TO_CONTROL); - } else { - TreeHelper.literalValueControl(mit.arguments().get(1), treesToReport, ARGUMENT_VALUE_TO_CONTROL); - } - } catch (Exception e) { - LOG.debug(String.format("[%s] Cannot evaluate requestLocationUpdates(...) argument value.", getClass().getName())); - LOG.debug("Exception:", e); + if (methodMatcher.matches(mit) && !mit.arguments().isEmpty()) { + ExpressionTree firstArgument = mit.arguments().get(0); + /* + * Here we want to know if the first parameter is a String, + * if it is, the minDistance Parameter will be at position 2 + * else, the minDistance will be at position 1 + */ + try { + if (firstArgument.symbolType().toString().equals("String") || firstArgument.is(Tree.Kind.NULL_LITERAL)) { + TreeHelper.literalValueControl(mit.arguments().get(2), treesToReport, ARGUMENT_VALUE_TO_CONTROL); + } else { + TreeHelper.literalValueControl(mit.arguments().get(1), treesToReport, ARGUMENT_VALUE_TO_CONTROL); } + } catch (Exception e) { + LOG.debug(String.format("{} Cannot evaluate requestLocationUpdates(...) argument value.", getClass().getName())); + LOG.debug("Exception: {}", e.getMessage(), e); } } } diff --git a/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/ThriftyGeolocationMinTimeRule.java b/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/ThriftyGeolocationMinTimeRule.java index 5567ade32..bf10ee500 100644 --- a/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/ThriftyGeolocationMinTimeRule.java +++ b/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/ThriftyGeolocationMinTimeRule.java @@ -56,24 +56,22 @@ public List nodesToVisit() { public void visitNode(Tree tree) { if (tree.is(Tree.Kind.METHOD_INVOCATION)) { MethodInvocationTree mit = (MethodInvocationTree) tree; - if (methodMatcher.matches(mit)) { - if (!mit.arguments().isEmpty()) { - ExpressionTree firstArgument = mit.arguments().get(0); - /* - * Here we want to know if the first parameter is a String, - * if it is, the minDistance Parameter will be at position 1 - * else, the minTime will be at position 0 - */ - try { - if (firstArgument.symbolType().toString().equals("String") || firstArgument.is(Tree.Kind.NULL_LITERAL)) { - TreeHelper.literalValueControl(mit.arguments().get(1), treesToReport, ARGUMENT_VALUE_TO_CONTROL); - } else { - TreeHelper.literalValueControl(mit.arguments().get(0), treesToReport, ARGUMENT_VALUE_TO_CONTROL); - } - } catch (Exception e) { - LOG.debug(String.format("[%s] Cannot evaluate requestLocationUpdates(...) argument value.", getClass().getName())); - LOG.debug("Exception:", e); + if (methodMatcher.matches(mit) && !mit.arguments().isEmpty()) { + ExpressionTree firstArgument = mit.arguments().get(0); + /* + * Here we want to know if the first parameter is a String, + * if it is, the minDistance Parameter will be at position 1 + * else, the minTime will be at position 0 + */ + try { + if (firstArgument.symbolType().toString().equals("String") || firstArgument.is(Tree.Kind.NULL_LITERAL)) { + TreeHelper.literalValueControl(mit.arguments().get(1), treesToReport, ARGUMENT_VALUE_TO_CONTROL); + } else { + TreeHelper.literalValueControl(mit.arguments().get(0), treesToReport, ARGUMENT_VALUE_TO_CONTROL); } + } catch (Exception e) { + LOG.debug(String.format("{} Cannot evaluate requestLocationUpdates(...) argument value.", getClass().getName())); + LOG.debug("Exception: {}", e.getMessage(), e); } } } diff --git a/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/VibrationFreeRule.java b/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/VibrationFreeRule.java index 4799c457a..438691c6f 100644 --- a/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/VibrationFreeRule.java +++ b/src/android-plugin/src/main/java/io/ecocode/java/checks/sobriety/VibrationFreeRule.java @@ -28,13 +28,15 @@ @Rule(key = "ESOB011", name = "ecocodeVibrationFree") public class VibrationFreeRule extends ArgumentValueOnMethodCheck { + + private static final String SYSTEM_SERVICE_METHOD = "getSystemService"; public VibrationFreeRule() { super(new MethodSpecs[]{ - new MethodSpecs("getSystemService", "android.content.Context", "vibrator", 0), - new MethodSpecs("getSystemService", "android.content.Context", "vibrator_manager", 0), - new MethodSpecs("getSystemService", "android.app.Activity", "vibrator", 0), - new MethodSpecs("getSystemService", "android.app.Activity", "vibrator_manager", 0) + new MethodSpecs(SYSTEM_SERVICE_METHOD, "android.content.Context", "vibrator", 0), + new MethodSpecs(SYSTEM_SERVICE_METHOD, "android.content.Context", "vibrator_manager", 0), + new MethodSpecs(SYSTEM_SERVICE_METHOD, "android.app.Activity", "vibrator", 0), + new MethodSpecs(SYSTEM_SERVICE_METHOD, "android.app.Activity", "vibrator_manager", 0) }); } diff --git a/src/android-plugin/src/main/java/io/ecocode/xml/checks/helpers/CheckPermissionsRule.java b/src/android-plugin/src/main/java/io/ecocode/xml/checks/helpers/CheckPermissionsRule.java index 7177a70cd..b57501ef4 100644 --- a/src/android-plugin/src/main/java/io/ecocode/xml/checks/helpers/CheckPermissionsRule.java +++ b/src/android-plugin/src/main/java/io/ecocode/xml/checks/helpers/CheckPermissionsRule.java @@ -31,7 +31,7 @@ public abstract class CheckPermissionsRule extends XPathCheck { private final String xpathManifestExpression; private final String errorMessage; - public CheckPermissionsRule(String permissionName, String errorMessage) { + protected CheckPermissionsRule(String permissionName, String errorMessage) { this.xpathManifestExpression = "//manifest/uses-permission/@name[. = \"" + permissionName + "\"]"; this.errorMessage = errorMessage; } diff --git a/src/android-plugin/src/main/java/io/ecocode/xml/checks/power/ChargeAwarenessXmlRule.java b/src/android-plugin/src/main/java/io/ecocode/xml/checks/power/ChargeAwarenessXmlRule.java index 7b95228fc..8c7c93b8d 100644 --- a/src/android-plugin/src/main/java/io/ecocode/xml/checks/power/ChargeAwarenessXmlRule.java +++ b/src/android-plugin/src/main/java/io/ecocode/xml/checks/power/ChargeAwarenessXmlRule.java @@ -33,11 +33,10 @@ public class ChargeAwarenessXmlRule extends XPathSimpleCheck { private String xPathActionPowerDisconnected = "//manifest/application/receiver/intent-filter/action/@name[.=\"android.intent.action.ACTION_POWER_DISCONNECTED\"]"; private String xPathActionBatteryOkay = "//manifest/application/receiver/intent-filter/action/@name[.=\"android.intent.action.BATTERY_OKAY\"]"; private String xPathActionBatteryLow = "//manifest/application/receiver/intent-filter/action/@name[.=\"android.intent.action.BATTERY_LOW\"]"; - private String INFO_MESSAGE = "Monitoring power changes and customizing behavior depending on battery level is a good practice."; @Override protected String getMessage() { - return INFO_MESSAGE; + return "Monitoring power changes and customizing behavior depending on battery level is a good practice."; } @Override diff --git a/src/android-plugin/src/test/java/io/ecocode/java/JavaEcoCodeProfileTest.java b/src/android-plugin/src/test/java/io/ecocode/java/JavaEcoCodeProfileTest.java index 3b6332bb5..e2c12b260 100644 --- a/src/android-plugin/src/test/java/io/ecocode/java/JavaEcoCodeProfileTest.java +++ b/src/android-plugin/src/test/java/io/ecocode/java/JavaEcoCodeProfileTest.java @@ -21,7 +21,7 @@ public void should_create_sonar_way_profile() { assertThat(profile.language()).isEqualTo(Java.KEY); assertThat(profile.name()).isEqualTo(Java.PROFILE_NAME); - assertThat(profile.rules().size()).isEqualTo(JavaCheckList.getJavaChecks().size()); + assertThat(profile.rules()).hasSameSizeAs(JavaCheckList.getJavaChecks()); assertThat(validation.hasErrors()).isFalse(); } } diff --git a/src/android-plugin/src/test/java/io/ecocode/xml/XmlEcoCodeProfileTest.java b/src/android-plugin/src/test/java/io/ecocode/xml/XmlEcoCodeProfileTest.java index 6e99f31c9..be8fde043 100644 --- a/src/android-plugin/src/test/java/io/ecocode/xml/XmlEcoCodeProfileTest.java +++ b/src/android-plugin/src/test/java/io/ecocode/xml/XmlEcoCodeProfileTest.java @@ -22,7 +22,7 @@ public void should_create_sonar_way_profile() { assertThat(profile.language()).isEqualTo(Xml.KEY); assertThat(profile.name()).isEqualTo(Xml.PROFILE_NAME); // "-1" because we do not want the rule "DarkUIBrightColors" in the profile - assertThat(profile.rules().size()).isEqualTo(XmlCheckList.getXmlChecks().size() - 1); + assertThat(profile.rules()).hasSize(XmlCheckList.getXmlChecks().size() - 1); assertThat(validation.hasErrors()).isFalse(); } } diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidSQLRequestInLoop.java b/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidSQLRequestInLoop.java index 7b33712ec..d59b786a3 100644 --- a/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidSQLRequestInLoop.java +++ b/src/java-plugin/src/main/java/fr/cnumr/java/checks/AvoidSQLRequestInLoop.java @@ -18,7 +18,35 @@ tags = {"bug" }) public class AvoidSQLRequestInLoop extends IssuableSubscriptionVisitor { - protected static final String MESSAGERULE = "Avoid SQL request in loop"; + protected static final String MESSAGERULE = "Avoid SQL request in loop"; + private static final String JAVA_SQL_STATEMENT = "java.sql.Statement"; + private static final String JAVA_SQL_CONNECTION = "java.sql.Connection"; + private static final String SPRING_JDBC_OPERATIONS = "org.springframework.jdbc.core.JdbcOperations"; + + private final MethodMatchers SQL_METHOD = MethodMatchers.or( + MethodMatchers.create().ofSubTypes("org.hibernate.Session").names("createQuery", "createSQLQuery") + .withAnyParameters().build(), + MethodMatchers.create().ofSubTypes(JAVA_SQL_STATEMENT) + .names("executeQuery", "execute", "executeUpdate", "executeLargeUpdate") // addBatch is recommended + .withAnyParameters().build(), + MethodMatchers.create().ofSubTypes(JAVA_SQL_CONNECTION) + .names("prepareStatement", "prepareCall", "nativeSQL") + .withAnyParameters().build(), + MethodMatchers.create().ofTypes("javax.persistence.EntityManager") + .names("createNativeQuery", "createQuery") + .withAnyParameters().build(), + MethodMatchers.create().ofSubTypes(SPRING_JDBC_OPERATIONS) + .names("batchUpdate", "execute", "query", "queryForList", "queryForMap", "queryForObject", + "queryForRowSet", "queryForInt", "queryForLong", "update") + .withAnyParameters().build(), + MethodMatchers.create().ofTypes("org.springframework.jdbc.core.PreparedStatementCreatorFactory") + .names(CONSTRUCTOR, "newPreparedStatementCreator") + .withAnyParameters().build(), + MethodMatchers.create().ofSubTypes("javax.jdo.PersistenceManager").names("newQuery") + .withAnyParameters().build(), + MethodMatchers.create().ofSubTypes("javax.jdo.Query").names("setFilter", "setGrouping") + .withAnyParameters().build()); + private final AvoidSQLRequestInLoopVisitor visitorInFile = new AvoidSQLRequestInLoopVisitor(); @Override @@ -35,34 +63,6 @@ public void visitNode(Tree tree) { private class AvoidSQLRequestInLoopVisitor extends BaseTreeVisitor { - private static final String JAVA_SQL_STATEMENT = "java.sql.Statement"; - private static final String JAVA_SQL_CONNECTION = "java.sql.Connection"; - private static final String SPRING_JDBC_OPERATIONS = "org.springframework.jdbc.core.JdbcOperations"; - - private final MethodMatchers SQL_METHOD = MethodMatchers.or( - MethodMatchers.create().ofSubTypes("org.hibernate.Session").names("createQuery", "createSQLQuery") - .withAnyParameters().build(), - MethodMatchers.create().ofSubTypes(JAVA_SQL_STATEMENT) - .names("executeQuery", "execute", "executeUpdate", "executeLargeUpdate") // addBatch is recommended - .withAnyParameters().build(), - MethodMatchers.create().ofSubTypes(JAVA_SQL_CONNECTION) - .names("prepareStatement", "prepareCall", "nativeSQL") - .withAnyParameters().build(), - MethodMatchers.create().ofTypes("javax.persistence.EntityManager") - .names("createNativeQuery", "createQuery") - .withAnyParameters().build(), - MethodMatchers.create().ofSubTypes(SPRING_JDBC_OPERATIONS) - .names("batchUpdate", "execute", "query", "queryForList", "queryForMap", "queryForObject", - "queryForRowSet", "queryForInt", "queryForLong", "update") - .withAnyParameters().build(), - MethodMatchers.create().ofTypes("org.springframework.jdbc.core.PreparedStatementCreatorFactory") - .names(CONSTRUCTOR, "newPreparedStatementCreator") - .withAnyParameters().build(), - MethodMatchers.create().ofSubTypes("javax.jdo.PersistenceManager").names("newQuery") - .withAnyParameters().build(), - MethodMatchers.create().ofSubTypes("javax.jdo.Query").names("setFilter", "setGrouping") - .withAnyParameters().build()); - @Override public void visitMethodInvocation(MethodInvocationTree tree) { if (SQL_METHOD.matches(tree)) { diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/checks/IncrementCheck.java b/src/java-plugin/src/main/java/fr/cnumr/java/checks/IncrementCheck.java index b2bc06f24..67b3b5938 100644 --- a/src/java-plugin/src/main/java/fr/cnumr/java/checks/IncrementCheck.java +++ b/src/java-plugin/src/main/java/fr/cnumr/java/checks/IncrementCheck.java @@ -5,7 +5,6 @@ import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; import org.sonar.plugins.java.api.tree.Tree; import org.sonar.plugins.java.api.tree.Tree.Kind; -import org.sonar.plugins.java.api.tree.UnaryExpressionTree; import java.util.Collections; import java.util.List; diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/checks/NoFunctionCallWhenDeclaringForLoop.java b/src/java-plugin/src/main/java/fr/cnumr/java/checks/NoFunctionCallWhenDeclaringForLoop.java index 1154458a5..1bbc5490b 100644 --- a/src/java-plugin/src/main/java/fr/cnumr/java/checks/NoFunctionCallWhenDeclaringForLoop.java +++ b/src/java-plugin/src/main/java/fr/cnumr/java/checks/NoFunctionCallWhenDeclaringForLoop.java @@ -20,18 +20,14 @@ import org.sonar.plugins.java.api.tree.PackageDeclarationTree; import org.sonar.plugins.java.api.tree.Tree; -@Rule( - key = "S69", - name = "Developpement", - description =NoFunctionCallWhenDeclaringForLoop.MESSAGERULE, - priority = Priority.MINOR, - tags = {"bug"}) +@Rule(key = "S69", name = "Developpement", description = NoFunctionCallWhenDeclaringForLoop.MESSAGERULE, priority = Priority.MINOR, tags = { + "bug" }) public class NoFunctionCallWhenDeclaringForLoop extends IssuableSubscriptionVisitor { - protected static final String MESSAGERULE = "Do not call a function when declaring a for-type loop"; + protected static final String MESSAGERULE = "Do not call a function when declaring a for-type loop"; private static final Map> linesWithIssuesByClass = new HashMap<>(); - + @Override public List nodesToVisit() { return Collections.singletonList(Tree.Kind.FOR_STATEMENT); @@ -45,88 +41,80 @@ public void visitNode(Tree tree) { if (null != condition) { method.condition().accept(invocationMethodVisitor); } - //update + // update // initaliser method.update().accept(invocationMethodVisitor); method.initializer().accept(invocationMethodVisitor); - } + } - private void repport(Tree tree) { - if (tree.firstToken() != null) { - final String classname = getFullyQualifiedNameOfClassOf(tree); - final int line = tree.firstToken().line(); + private class MethodInvocationInForStatementVisitor extends BaseTreeVisitor { - if (!linesWithIssuesByClass.containsKey(classname)) { - linesWithIssuesByClass.put(classname, new ArrayList<>()); + @Override + public void visitMethodInvocation(MethodInvocationTree tree) { + if (!lineAlreadyHasThisIssue(tree)) { + report(tree); + return; } - - linesWithIssuesByClass.get(classname).add(line); + super.visitMethodInvocation(tree); } - reportIssue(tree, MESSAGERULE); - } - + private boolean lineAlreadyHasThisIssue(Tree tree) { + if (tree.firstToken() != null) { + final String classname = getFullyQualifiedNameOfClassOf(tree); + final int line = tree.firstToken().line(); + return linesWithIssuesByClass.containsKey(classname) + && linesWithIssuesByClass.get(classname).contains(line); + } - private String getFullyQualifiedNameOfClassOf(Tree tree) { - Tree parent = tree.parent(); + return false; + } - while (parent != null) { - final Tree grandparent = parent.parent(); + private void report(Tree tree) { + if (tree.firstToken() != null) { + final String classname = getFullyQualifiedNameOfClassOf(tree); + final int line = tree.firstToken().line(); - if (parent.is(Tree.Kind.CLASS) && grandparent != null && grandparent.is(Tree.Kind.COMPILATION_UNIT)) { - final String packageName = getPackageName((CompilationUnitTree) grandparent); + linesWithIssuesByClass.computeIfAbsent(classname, k -> new ArrayList<>()); - return packageName.isEmpty() - ? getClassName((ClassTree) parent) - : packageName + '.' + getClassName((ClassTree) parent); + linesWithIssuesByClass.get(classname).add(line); } - parent = parent.parent(); + reportIssue(tree, MESSAGERULE); } - return ""; - } + private String getFullyQualifiedNameOfClassOf(Tree tree) { + Tree parent = tree.parent(); + while (parent != null) { + final Tree grandparent = parent.parent(); - private String getPackageName(CompilationUnitTree compilationUnitTree) { - final PackageDeclarationTree packageDeclarationTree = compilationUnitTree.packageDeclaration(); - if (packageDeclarationTree == null) { - return ""; - } + if (parent.is(Tree.Kind.CLASS) && grandparent != null && grandparent.is(Tree.Kind.COMPILATION_UNIT)) { + final String packageName = getPackageName((CompilationUnitTree) grandparent); - return packageDeclarationTree.packageName().toString(); - } + return packageName.isEmpty() ? getClassName((ClassTree) parent) + : packageName + '.' + getClassName((ClassTree) parent); + } - private String getClassName(ClassTree classTree) { - final IdentifierTree simpleName = classTree.simpleName(); - return simpleName == null - ? "" - : simpleName.toString(); - } + parent = parent.parent(); + } - private class MethodInvocationInForStatementVisitor extends BaseTreeVisitor { + return ""; + } + + private String getPackageName(CompilationUnitTree compilationUnitTree) { + final PackageDeclarationTree packageDeclarationTree = compilationUnitTree.packageDeclaration(); + if (packageDeclarationTree == null) { + return ""; + } - @Override - public void visitMethodInvocation(MethodInvocationTree tree) { - if (!lineAlreadyHasThisIssue(tree)) { - repport(tree); - return; - } - super.visitMethodInvocation(tree); - } - - private boolean lineAlreadyHasThisIssue(Tree tree) { - if (tree.firstToken() != null) { - final String classname = getFullyQualifiedNameOfClassOf(tree); - final int line = tree.firstToken().line(); - - return linesWithIssuesByClass.containsKey(classname) - && linesWithIssuesByClass.get(classname).contains(line); - } - - return false; - } + return packageDeclarationTree.packageName().toString(); + } + + private String getClassName(ClassTree classTree) { + final IdentifierTree simpleName = classTree.simpleName(); + return simpleName == null ? "" : simpleName.toString(); + } } } diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/checks/UnnecessarilyAssignValuesToVariables.java b/src/java-plugin/src/main/java/fr/cnumr/java/checks/UnnecessarilyAssignValuesToVariables.java index 151d0ba14..842236756 100644 --- a/src/java-plugin/src/main/java/fr/cnumr/java/checks/UnnecessarilyAssignValuesToVariables.java +++ b/src/java-plugin/src/main/java/fr/cnumr/java/checks/UnnecessarilyAssignValuesToVariables.java @@ -39,8 +39,8 @@ public class UnnecessarilyAssignValuesToVariables extends BaseTreeVisitor implem private JavaFileScannerContext context; private String lastTypeForMessage; - private Map variableList = new HashMap(); - private static final Map> linesWithIssuesByVariable = new HashMap>(); + private Map variableList = new HashMap<>(); + private static final Map> linesWithIssuesByVariable = new HashMap<>(); @Override public void scanFile(JavaFileScannerContext context) { @@ -57,7 +57,7 @@ public void visitBlock(BlockTree tree) { tree.accept(getVariableVisitor); tree.accept(checkVariable); - variableList.forEach((name, varTree) -> reportIfUnknow(name, varTree)); + variableList.forEach(this::reportIfUnknow); variableList.clear(); } diff --git a/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaRulesDefinitionTest.java b/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaRulesDefinitionTest.java index 842fca9ef..67525fcf5 100644 --- a/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaRulesDefinitionTest.java +++ b/src/java-plugin/src/test/java/fr/cnumr/java/MyJavaRulesDefinitionTest.java @@ -22,7 +22,6 @@ import org.junit.jupiter.api.Test; import org.sonar.api.rules.RuleType; import org.sonar.api.server.debt.DebtRemediationFunction.Type; -import org.sonar.api.server.rule.RuleParamType; import org.sonar.api.server.rule.RulesDefinition; import org.sonar.api.server.rule.RulesDefinition.Param; import org.sonar.api.server.rule.RulesDefinition.Repository; diff --git a/src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidSpringRepositoryCallInLoopCheckTest.java b/src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidSpringRepositoryCallInLoopCheckTest.java index d3a5c30e5..ceeffae91 100644 --- a/src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidSpringRepositoryCallInLoopCheckTest.java +++ b/src/java-plugin/src/test/java/fr/cnumr/java/checks/AvoidSpringRepositoryCallInLoopCheckTest.java @@ -5,7 +5,7 @@ import fr.cnumr.java.utils.FilesUtils; -public class AvoidSpringRepositoryCallInLoopCheckTest { +class AvoidSpringRepositoryCallInLoopCheckTest { @Test void test() { diff --git a/src/java-plugin/src/test/java/fr/cnumr/java/checks/NoFunctionCallWhenDeclaringForLoopTest.java b/src/java-plugin/src/test/java/fr/cnumr/java/checks/NoFunctionCallWhenDeclaringForLoopTest.java index 45473ead8..d0ff2e1a4 100644 --- a/src/java-plugin/src/test/java/fr/cnumr/java/checks/NoFunctionCallWhenDeclaringForLoopTest.java +++ b/src/java-plugin/src/test/java/fr/cnumr/java/checks/NoFunctionCallWhenDeclaringForLoopTest.java @@ -3,7 +3,7 @@ import org.junit.jupiter.api.Test; import org.sonar.java.checks.verifier.JavaCheckVerifier; -public class NoFunctionCallWhenDeclaringForLoopTest { +class NoFunctionCallWhenDeclaringForLoopTest { @Test void test() { JavaCheckVerifier.newVerifier() diff --git a/src/php-plugin/src/main/java/fr/cnumr/php/checks/AvoidDoubleQuoteCheck.java b/src/php-plugin/src/main/java/fr/cnumr/php/checks/AvoidDoubleQuoteCheck.java index ec3abd99d..0c3fc4212 100644 --- a/src/php-plugin/src/main/java/fr/cnumr/php/checks/AvoidDoubleQuoteCheck.java +++ b/src/php-plugin/src/main/java/fr/cnumr/php/checks/AvoidDoubleQuoteCheck.java @@ -35,7 +35,6 @@ public void checkIssue(LiteralTree literalTree) { if (lineAlreadyHasThisIssue(literalTree)) return; if (literalTree.value().indexOf("\"") == 0 && literalTree.value().lastIndexOf("\"") == literalTree.value().length() - 1) { repport(literalTree); - return; } } @@ -44,9 +43,7 @@ private void repport(LiteralTree literalTree) { final String classname = context().getPhpFile().toString(); final int line = literalTree.token().line(); - if (!linesWithIssuesByFile.containsKey(classname)) { - linesWithIssuesByFile.put(classname, new ArrayList<>()); - } + linesWithIssuesByFile.computeIfAbsent(classname, k -> new ArrayList<>()); linesWithIssuesByFile.get(classname).add(line); } context().newIssue(this, literalTree, ERROR_MESSAGE); diff --git a/src/php-plugin/src/main/java/fr/cnumr/php/checks/AvoidFullSQLRequestCheck.java b/src/php-plugin/src/main/java/fr/cnumr/php/checks/AvoidFullSQLRequestCheck.java index 37761d61e..b88a08dfc 100644 --- a/src/php-plugin/src/main/java/fr/cnumr/php/checks/AvoidFullSQLRequestCheck.java +++ b/src/php-plugin/src/main/java/fr/cnumr/php/checks/AvoidFullSQLRequestCheck.java @@ -21,7 +21,7 @@ public class AvoidFullSQLRequestCheck extends PHPSubscriptionCheck { public static final String ERROR_MESSAGE = "Don't use the query SELECT * FROM"; - private static final String RegExpSelectFrom = "(?i).*select.*\\*.*from.*"; + private static final String REGEXPSELECTFROM = "(?i).*select.*\\*.*from.*"; @Override public List nodesToVisit() { @@ -32,7 +32,7 @@ public List nodesToVisit() { public void visitNode(Tree tree) { LiteralTree literal = (LiteralTree) tree; - if(literal.value().matches(RegExpSelectFrom)) + if(literal.value().matches(REGEXPSELECTFROM)) context().newIssue(this, tree, ERROR_MESSAGE); } diff --git a/src/php-plugin/src/main/java/fr/cnumr/php/checks/AvoidSQLRequestInLoopCheck.java b/src/php-plugin/src/main/java/fr/cnumr/php/checks/AvoidSQLRequestInLoopCheck.java index 02aac2ffe..163d14bf9 100644 --- a/src/php-plugin/src/main/java/fr/cnumr/php/checks/AvoidSQLRequestInLoopCheck.java +++ b/src/php-plugin/src/main/java/fr/cnumr/php/checks/AvoidSQLRequestInLoopCheck.java @@ -1,71 +1,74 @@ package fr.cnumr.php.checks; +import java.util.Arrays; +import java.util.List; +import java.util.regex.Pattern; + import org.sonar.check.Priority; import org.sonar.check.Rule; import org.sonar.plugins.php.api.tree.Tree; import org.sonar.plugins.php.api.tree.Tree.Kind; -import org.sonar.plugins.php.api.tree.statement.*; +import org.sonar.plugins.php.api.tree.statement.BlockTree; +import org.sonar.plugins.php.api.tree.statement.DoWhileStatementTree; +import org.sonar.plugins.php.api.tree.statement.ExpressionStatementTree; +import org.sonar.plugins.php.api.tree.statement.ForEachStatementTree; +import org.sonar.plugins.php.api.tree.statement.ForStatementTree; +import org.sonar.plugins.php.api.tree.statement.IfStatementTree; +import org.sonar.plugins.php.api.tree.statement.StatementTree; import org.sonar.plugins.php.api.visitors.PHPSubscriptionCheck; -import java.util.Arrays; -import java.util.List; -import java.util.regex.Pattern; - @Rule( - key = "S72", - name = "Developpement", - description = AvoidSQLRequestInLoopCheck.ERROR_MESSAGE, - priority = Priority.MINOR, - tags = {"bug" } + key = "S72", + name = "Developpement", description = AvoidSQLRequestInLoopCheck.ERROR_MESSAGE, + priority = Priority.MINOR, + tags = { "bug" } ) - public class AvoidSQLRequestInLoopCheck extends PHPSubscriptionCheck { - public static final String ERROR_MESSAGE = "Avoid SQL request in loop"; - private static final Pattern RegExSQLCall = Pattern.compile("(mysql(i::|_)query\\s*\\(.*)|(oci_execute\\(.*)"); + public static final String ERROR_MESSAGE = "Avoid SQL request in loop"; + private static final Pattern RegExSQLCall = Pattern.compile("(mysql(i::|_)query\\s*\\(.*)|(oci_execute\\(.*)"); - @Override - public List nodesToVisit() { - return Arrays.asList(Kind.FOR_STATEMENT, Kind.FOREACH_STATEMENT, Kind.DO_WHILE_STATEMENT); - } + @Override + public List nodesToVisit() { + return Arrays.asList(Kind.FOR_STATEMENT, Kind.FOREACH_STATEMENT, Kind.DO_WHILE_STATEMENT); + } - @Override - public void visitNode(Tree tree) { - if(tree.is(Kind.FOR_STATEMENT)) - visitBlockNode((BlockTree) ((ForStatementTree)tree).statements().get(0)); + @Override + public void visitNode(Tree tree) { + if (tree.is(Kind.FOR_STATEMENT)) + visitBlockNode((BlockTree) ((ForStatementTree) tree).statements().get(0)); - if(tree.is(Kind.FOREACH_STATEMENT)) - visitBlockNode((BlockTree) ((ForEachStatementTree)tree).statements().get(0)); + if (tree.is(Kind.FOREACH_STATEMENT)) + visitBlockNode((BlockTree) ((ForEachStatementTree) tree).statements().get(0)); - if(tree.is(Kind.DO_WHILE_STATEMENT)) - visitBlockNode((BlockTree) ((DoWhileStatementTree)tree).statement()); - } + if (tree.is(Kind.DO_WHILE_STATEMENT)) + visitBlockNode((BlockTree) ((DoWhileStatementTree) tree).statement()); + } - private void visitBlockNode(BlockTree block) - { - block.statements().forEach(this::VisiteChildNode); - } + private void visitBlockNode(BlockTree block) { + block.statements().forEach(this::visiteChildNode); + } - private void VisiteChildNode(Tree tree) { - if (tree.is(Kind.EXPRESSION_STATEMENT)) { - ExpressionStatementTree expressionStatementTree = (ExpressionStatementTree) tree; - String expression = expressionStatementTree.expression().toString(); - VerifyIfThereIsAError(expression, expressionStatementTree); - } + private void visiteChildNode(Tree tree) { + if (tree.is(Kind.EXPRESSION_STATEMENT)) { + ExpressionStatementTree expressionStatementTree = (ExpressionStatementTree) tree; + String expression = expressionStatementTree.expression().toString(); + verifyIfThereIsAError(expression, expressionStatementTree); + } - if (tree.is(Kind.IF_STATEMENT)) { - StatementTree statementTree = ((IfStatementTree) tree).statements().get(0); - if (statementTree.is(Kind.BLOCK)) - visitBlockNode((BlockTree) statementTree); - else - VisiteChildNode(statementTree); - } - } + if (tree.is(Kind.IF_STATEMENT)) { + StatementTree statementTree = ((IfStatementTree) tree).statements().get(0); + if (statementTree.is(Kind.BLOCK)) { + visitBlockNode((BlockTree) statementTree); + } else { + visiteChildNode(statementTree); + } + } + } - private void VerifyIfThereIsAError(String expression, ExpressionStatementTree expressionStatementTree) - { - if (RegExSQLCall.matcher(expression).find()) - context().newIssue(this, expressionStatementTree, ERROR_MESSAGE); - } + private void verifyIfThereIsAError(String expression, ExpressionStatementTree expressionStatementTree) { + if (RegExSQLCall.matcher(expression).find()) + context().newIssue(this, expressionStatementTree, ERROR_MESSAGE); + } } diff --git a/src/php-plugin/src/main/java/fr/cnumr/php/checks/NoFunctionCallWhenDeclaringForLoop.java b/src/php-plugin/src/main/java/fr/cnumr/php/checks/NoFunctionCallWhenDeclaringForLoop.java index 0e235d648..ed06ac9c6 100644 --- a/src/php-plugin/src/main/java/fr/cnumr/php/checks/NoFunctionCallWhenDeclaringForLoop.java +++ b/src/php-plugin/src/main/java/fr/cnumr/php/checks/NoFunctionCallWhenDeclaringForLoop.java @@ -36,9 +36,7 @@ public void visitNode(Tree tree) { } public void checkExpressionsTree(SeparatedList treeSeparatedList) { - treeSeparatedList.forEach(expressionTree -> { - checkBothSideExpression(expressionTree); - }); + treeSeparatedList.forEach(this::checkBothSideExpression); } public void checkBothSideExpression(ExpressionTree expressionTree) { diff --git a/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidFullSQLRequest.java b/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidFullSQLRequest.java index 7a2124954..91b9c872a 100644 --- a/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidFullSQLRequest.java +++ b/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidFullSQLRequest.java @@ -35,16 +35,13 @@ public void initialize(Context context) { public void visitNodeString(SubscriptionContext ctx) { StringLiteral stringLiteral = (StringLiteral) ctx.syntaxNode(); - stringLiteral.stringElements().forEach(stringElement -> { - checkIssue(stringElement, ctx); - }); + stringLiteral.stringElements().forEach(stringElement -> checkIssue(stringElement, ctx)); } public void checkIssue(StringElement stringElement, SubscriptionContext ctx) { if (lineAlreadyHasThisIssue(stringElement, ctx)) return; if (stringElement.value().matches(REGEXPSELECTFROM)) { repport(stringElement, ctx); - return; } } @@ -52,9 +49,7 @@ private void repport(StringElement stringElement, SubscriptionContext ctx) { if (stringElement.firstToken() != null) { final String classname = ctx.pythonFile().fileName(); final int line = stringElement.firstToken().line(); - if (!linesWithIssuesByFile.containsKey(classname)) { - linesWithIssuesByFile.put(classname, new ArrayList<>()); - } + linesWithIssuesByFile.computeIfAbsent(classname, k -> new ArrayList<>()); linesWithIssuesByFile.get(classname).add(line); } ctx.addIssue(stringElement, MESSAGERULE); diff --git a/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidGlobalVariableInFunctionCheck.java b/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidGlobalVariableInFunctionCheck.java index 9583127c9..5950aea27 100644 --- a/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidGlobalVariableInFunctionCheck.java +++ b/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidGlobalVariableInFunctionCheck.java @@ -1,19 +1,65 @@ package fr.cnumr.python.checks; -import org.sonar.api.utils.log.Logger; -import org.sonar.api.utils.log.Loggers; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import org.sonar.check.Priority; import org.sonar.check.Rule; import org.sonar.plugins.python.api.PythonSubscriptionCheck; import org.sonar.plugins.python.api.SubscriptionCheck; import org.sonar.plugins.python.api.SubscriptionContext; import org.sonar.plugins.python.api.symbols.Symbol; -import org.sonar.plugins.python.api.tree.*; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import org.sonar.plugins.python.api.tree.AnnotatedAssignment; +import org.sonar.plugins.python.api.tree.ArgList; +import org.sonar.plugins.python.api.tree.AssertStatement; +import org.sonar.plugins.python.api.tree.AssignmentExpression; +import org.sonar.plugins.python.api.tree.AssignmentStatement; +import org.sonar.plugins.python.api.tree.AwaitExpression; +import org.sonar.plugins.python.api.tree.BinaryExpression; +import org.sonar.plugins.python.api.tree.CallExpression; +import org.sonar.plugins.python.api.tree.CompoundAssignmentStatement; +import org.sonar.plugins.python.api.tree.ComprehensionExpression; +import org.sonar.plugins.python.api.tree.ComprehensionFor; +import org.sonar.plugins.python.api.tree.ComprehensionIf; +import org.sonar.plugins.python.api.tree.ConditionalExpression; +import org.sonar.plugins.python.api.tree.DictCompExpression; +import org.sonar.plugins.python.api.tree.DictionaryLiteral; +import org.sonar.plugins.python.api.tree.ElseClause; +import org.sonar.plugins.python.api.tree.ExceptClause; +import org.sonar.plugins.python.api.tree.ExecStatement; +import org.sonar.plugins.python.api.tree.ExpressionList; +import org.sonar.plugins.python.api.tree.ExpressionStatement; +import org.sonar.plugins.python.api.tree.FileInput; +import org.sonar.plugins.python.api.tree.FinallyClause; +import org.sonar.plugins.python.api.tree.ForStatement; +import org.sonar.plugins.python.api.tree.FunctionDef; +import org.sonar.plugins.python.api.tree.IfStatement; +import org.sonar.plugins.python.api.tree.KeyValuePair; +import org.sonar.plugins.python.api.tree.LambdaExpression; +import org.sonar.plugins.python.api.tree.ListLiteral; +import org.sonar.plugins.python.api.tree.Name; +import org.sonar.plugins.python.api.tree.Parameter; +import org.sonar.plugins.python.api.tree.ParameterList; +import org.sonar.plugins.python.api.tree.ParenthesizedExpression; +import org.sonar.plugins.python.api.tree.PrintStatement; +import org.sonar.plugins.python.api.tree.RaiseStatement; +import org.sonar.plugins.python.api.tree.RegularArgument; +import org.sonar.plugins.python.api.tree.ReprExpression; +import org.sonar.plugins.python.api.tree.ReturnStatement; +import org.sonar.plugins.python.api.tree.SetLiteral; +import org.sonar.plugins.python.api.tree.StatementList; +import org.sonar.plugins.python.api.tree.SubscriptionExpression; +import org.sonar.plugins.python.api.tree.Tree; +import org.sonar.plugins.python.api.tree.TryStatement; +import org.sonar.plugins.python.api.tree.Tuple; +import org.sonar.plugins.python.api.tree.TupleParameter; +import org.sonar.plugins.python.api.tree.UnaryExpression; +import org.sonar.plugins.python.api.tree.UnpackingExpression; +import org.sonar.plugins.python.api.tree.WhileStatement; +import org.sonar.plugins.python.api.tree.YieldExpression; +import org.sonar.plugins.python.api.tree.YieldStatement; @Rule( key = AvoidGlobalVariableInFunctionCheck.RULE_KEY, @@ -22,7 +68,6 @@ priority = Priority.MINOR, tags = {"bug"}) public class AvoidGlobalVariableInFunctionCheck extends PythonSubscriptionCheck { - private static final Logger LOGGER = Loggers.get(AvoidGlobalVariableInFunctionCheck.class); public static final String RULE_KEY = "D4"; public static final String DESCRIPTION = "Use local variable (function/class scope) instead of global variable (application scope)"; diff --git a/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidTryCatchFinallyCheck.java b/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidTryCatchFinallyCheck.java index 9e626bd32..60f4c0ab0 100644 --- a/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidTryCatchFinallyCheck.java +++ b/src/python-plugin/src/main/java/fr/cnumr/python/checks/AvoidTryCatchFinallyCheck.java @@ -4,8 +4,6 @@ import org.sonar.check.Rule; import org.sonar.plugins.python.api.PythonSubscriptionCheck; import org.sonar.plugins.python.api.SubscriptionContext; -import org.sonar.plugins.python.api.symbols.Symbol; -import org.sonar.plugins.python.api.tree.CallExpression; import org.sonar.plugins.python.api.tree.Tree; import org.sonar.plugins.python.api.tree.TryStatement; diff --git a/src/python-plugin/src/main/java/fr/cnumr/python/checks/NoFunctionCallWhenDeclaringForLoop.java b/src/python-plugin/src/main/java/fr/cnumr/python/checks/NoFunctionCallWhenDeclaringForLoop.java index 5a2911ad8..a099b3825 100644 --- a/src/python-plugin/src/main/java/fr/cnumr/python/checks/NoFunctionCallWhenDeclaringForLoop.java +++ b/src/python-plugin/src/main/java/fr/cnumr/python/checks/NoFunctionCallWhenDeclaringForLoop.java @@ -4,11 +4,7 @@ import org.sonar.check.Rule; import org.sonar.plugins.python.api.PythonSubscriptionCheck; import org.sonar.plugins.python.api.tree.CallExpression; -import org.sonar.plugins.python.api.tree.ForStatement; import org.sonar.plugins.python.api.tree.Tree; -import org.sonar.python.tree.ForStatementImpl; - -import java.util.List; @Rule( key = NoFunctionCallWhenDeclaringForLoop.RULE_KEY, From 31bd8dbfe74c231445996864744e30cacc85dcfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Le=20Goa=C3=ABr?= Date: Mon, 14 Nov 2022 11:49:26 +0100 Subject: [PATCH 114/119] Update work-packages.md --- hackathon/work-packages.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hackathon/work-packages.md b/hackathon/work-packages.md index 7298b7842..b74b7531b 100644 --- a/hackathon/work-packages.md +++ b/hackathon/work-packages.md @@ -71,7 +71,7 @@ The set of rules comes from the detailed [Energy Smells catalog](https://olegoae | EREL004 | Same dependencies | Gradle | | EREL005 | Duplicate dependencies | Gradle | | EREL007 | Clear cache | Java | -| EREL008 | Concert to WebP | File System | +| EREL008 | Convert to WebP | File System | | EREL009 | Shrink Resources | Gradle | | EREL010 | Disable Obfuscation | Gradle | From b3d0751c5b3c2094e8201826dca7114cd2fcfcf0 Mon Sep 17 00:00:00 2001 From: oussamaLaribi <63214114+oussamaLaribi@users.noreply.github.com> Date: Tue, 15 Nov 2022 16:32:47 +0100 Subject: [PATCH 115/119] Adjust rule D1 PHP (#179) * Adapt the description of the rules * Adjust rule D1 PHP * Format D1 --- .../main/resources/fr/cnumr/l10n/php/rules/custom/D1.html | 8 ++++++-- .../main/resources/fr/cnumr/l10n/php/rules/custom/D1.json | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/D1.html b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/D1.html index 5444a6196..bb0a8af13 100644 --- a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/D1.html +++ b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/D1.html @@ -1,5 +1,4 @@ -

Inside complex code parts (for exemple multiple loops, complex data constructions...), avoid using try...catch...finally.

-

When an exception is thrown, a variable (the exception itself) is created in a catch block and it's destruction consumes unnecessary CPU cycles and RAM. Prefer using logical tests in this cases.

+

Inside complex code parts (for exemple multiple loops, complex data constructions...), avoid using finally in try/catch. It will save CPU cycles consumption.

Noncompliant Code Example

 try
@@ -11,6 +10,9 @@ 

Noncompliant Code Example

$msg = "Error opening $imgFile for Product $row['Identifier']"; throw new Exception($msg); } +finally { + $msg = "bloc finally"; +}

Compliant Solution

@@ -25,4 +27,6 @@

Compliant Solution

$msg = "Error opening $imgFile for Product $row['Identifier']"; print $msg; } +//finally +print $msg; diff --git a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/D1.json b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/D1.json index 72a37f621..0e8cedb16 100644 --- a/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/D1.json +++ b/src/php-plugin/src/main/resources/fr/cnumr/l10n/php/rules/custom/D1.json @@ -1,5 +1,5 @@ { - "title": "Avoid using try-catch-finally statement", + "title": "Avoid using finally in try/catch", "type": "CODE_SMELL", "status": "ready", "remediation": { From 55fa7e2889d1c2a0beb5d8ba0e295707f25a27a4 Mon Sep 17 00:00:00 2001 From: oussamaLaribi <63214114+oussamaLaribi@users.noreply.github.com> Date: Wed, 16 Nov 2022 18:19:34 +0100 Subject: [PATCH 116/119] Adjust rule description (#180) --- .../fr/cnumr/java/checks/ArrayCopyCheck.java | 2 +- .../cnumr/l10n/java/rules/java/GRPS0027.html | 18 +++++++++--------- .../cnumr/l10n/java/rules/java/GRPS0027.json | 2 +- .../fr/cnumr/l10n/python/rules/python/D7.json | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/java-plugin/src/main/java/fr/cnumr/java/checks/ArrayCopyCheck.java b/src/java-plugin/src/main/java/fr/cnumr/java/checks/ArrayCopyCheck.java index 59d77ce81..9ce3cbb7c 100644 --- a/src/java-plugin/src/main/java/fr/cnumr/java/checks/ArrayCopyCheck.java +++ b/src/java-plugin/src/main/java/fr/cnumr/java/checks/ArrayCopyCheck.java @@ -40,7 +40,7 @@ public class ArrayCopyCheck extends IssuableSubscriptionVisitor { //@formatter:on - protected static final String MESSAGERULE = "Utiliser System.arraycopy pour copier des arrays"; + protected static final String MESSAGERULE = "Use System.arraycopy to copy arrays"; @Override public List nodesToVisit() { diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRPS0027.html b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRPS0027.html index 77d802ada..27836aad5 100644 --- a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRPS0027.html +++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRPS0027.html @@ -1,13 +1,13 @@ -

Utiliser System.arraycopy pour copier des arrays

+

Using System.arraycopy to copy arrays

-Les programmes passent la plupart du temps dans des boucles. Celles-ci peuvent �tre consommatrices en ressource, plus particuli�rement quand elles int�grent des traitements lourds (acc�s IO�). De plus, la taille des donn�es et des traitements � l�int�rieur des boucles ne va pas permettre d�utiliser pleinement les m�canismes mat�riels tels le cache ou les m�canismes d�optimisation des compilateurs.
-La copie d�array est par exemple potentiellement une source de non-performance si elle est mal con�ue. En effet, l�utilisation d�une simple boucle de recopie peut �tre deux fois plus consommatrice que des m�thodes d�di�es.
-Les boucles doivent �tre optimis�es pour diminuer le temps de traitement et utiliser pleinement les m�canismes et optimisations mat�riels et processeurs.
-Dans le cas de la recopie de tableau (array), on utilisera la m�thode native System.arraycopy.
-On pourra aussi utiliser copyOf ou clone qui sont l�g�rement moins performantes.
-On proscrira la m�thode de recopie par boucle. + Programs spend most of the time in loops. These can be resource consuming, especially when they integrate heavy processing (IO access). Moreover, the size of the data and processing inside the loops will not allow full use of hardware mechanisms such as the cache or compiler optimization mechanisms.
+ For example, an array copy is potentially a non-performance source if it is poorly designed. Indeed, the use of a single copy loop can be twice as consuming as dedicated methods.
+ Loops must be optimized to reduce processing time and make full use of hardware and processor mechanisms and optimizations.
+ In the case of table copying (table), the native System.arraycopy.
+ We can also use copyOf or clone that are slightly less efficient.
+ The looping method will be outlawed.

-

M�thode � proscrire :

+

Noncompliant Code Example

 	int len = array.length;
 	boolean[] copy = new boolean[array.length];
@@ -16,7 +16,7 @@
 	}
 	return copy;
 
-

M�thode � privil�gier :

+

Compliant Solution

 	int[] copy = new int[array.length];
 	System.arraycopy(array, 0, copy, 0, array.length);
diff --git a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRPS0027.json b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRPS0027.json
index c396965be..75c6da3cc 100644
--- a/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRPS0027.json
+++ b/src/java-plugin/src/main/resources/fr/cnumr/l10n/java/rules/java/GRPS0027.json
@@ -1,5 +1,5 @@
 {
-  "title": "Utiliser System.arraycopy pour copier des arrays",
+  "title": "Use System.arraycopy to copy arrays",
   "type": "CODE_SMELL",
   "status": "ready",
   "remediation": {
diff --git a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/D7.json b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/D7.json
index e32253fc5..a7c28bf70 100644
--- a/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/D7.json
+++ b/src/python-plugin/src/main/resources/fr/cnumr/l10n/python/rules/python/D7.json
@@ -1,5 +1,5 @@
 {
-    "title": "Eviter de créer des méthodes getter et setter dans les classes.",
+    "title": "Avoid creating getter and setter methods in classes.",
     "type": "CODE_SMELL",
     "status": "ready",
     "remediation": {

From cb7e3a0846f3dea800fae1ea8a5df26d5f466c6b Mon Sep 17 00:00:00 2001
From: dedece35 
Date: Tue, 8 Nov 2022 20:42:26 +0100
Subject: [PATCH 117/119] Correction of command maven warnings - optmisation
 plugins maven

---
 src/android-plugin/pom.xml | 47 ++++++++++++++++---------------------
 src/java-plugin/pom.xml    | 48 +++++++++++++++++---------------------
 src/php-plugin/pom.xml     |  2 +-
 3 files changed, 42 insertions(+), 55 deletions(-)

diff --git a/src/android-plugin/pom.xml b/src/android-plugin/pom.xml
index 6d80f8645..ee87c568c 100644
--- a/src/android-plugin/pom.xml
+++ b/src/android-plugin/pom.xml
@@ -240,32 +240,6 @@
 				
 			
 
-			
-				org.apache.maven.plugins
-				maven-dependency-plugin
-				
-					
-						copy-bundle
-						package
-						
-							copy
-						
-						
-							
-								
-									${project.groupId}
-									${project.artifactId}
-									${project.version}
-									jar
-									true
-								
-							
-							../lib
-						
-					
-				
-			
-
 			
 				org.apache.maven.plugins
 				maven-compiler-plugin
@@ -302,12 +276,31 @@
 				
 			
 
-			
 			
 				org.apache.maven.plugins
 				maven-dependency-plugin
 				2.10
 				
+					
+						copy-bundle
+						package
+						
+							copy
+						
+						
+							
+								
+									${project.groupId}
+									${project.artifactId}
+									${project.version}
+									jar
+									true
+								
+							
+							../lib
+						
+					
+					
 					
 						copy
 						test-compile
diff --git a/src/java-plugin/pom.xml b/src/java-plugin/pom.xml
index a63ad3b67..535a10fa0 100644
--- a/src/java-plugin/pom.xml
+++ b/src/java-plugin/pom.xml
@@ -86,31 +86,6 @@
                     
                 
             
-            
-                org.apache.maven.plugins
-                maven-dependency-plugin
-                
-                    
-                        copy-bundle
-                        package
-                        
-                    	copy
-                        
-                        
-                        
-                            
-                            ${project.groupId}
-                            ${project.artifactId}
-                            ${project.version}
-                            jar
-                            true
-                            
-                        
-                        ../lib
-                        
-                    
-                
-            
 
             
                 org.jacoco
@@ -132,16 +107,35 @@
                 
             
 
-            
             
                 org.apache.maven.plugins
                 maven-dependency-plugin
                 
+                    
+                        copy-bundle
+                        package
+                        
+                            copy
+                        
+                        
+                        
+                            
+                            ${project.groupId}
+                            ${project.artifactId}
+                            ${project.version}
+                            jar
+                            true
+                            
+                        
+                        ../lib
+                        
+                    
+                    
                     
                         copy
                         test-compile
                         
-                            copy
+                           copy
                         
                         
                             
diff --git a/src/php-plugin/pom.xml b/src/php-plugin/pom.xml
index 55c0832c6..2efa1b78f 100644
--- a/src/php-plugin/pom.xml
+++ b/src/php-plugin/pom.xml
@@ -55,7 +55,7 @@
                         copy-bundle
                         package
                         
-                        copy
+                            copy
                         
                         
                         

From 0ad827163c973a0deb701752c6249a88b6298d88 Mon Sep 17 00:00:00 2001
From: dedece35 
Date: Wed, 9 Nov 2022 12:18:11 +0100
Subject: [PATCH 118/119] correction maven warn : duplicated dependency

---
 src/android-plugin/pom.xml | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/src/android-plugin/pom.xml b/src/android-plugin/pom.xml
index ee87c568c..f1cb6ff4a 100644
--- a/src/android-plugin/pom.xml
+++ b/src/android-plugin/pom.xml
@@ -109,12 +109,6 @@
 			test
 		
 
-		
-			commons-lang
-			commons-lang
-			2.6
-		
-
 		
 			com.google.guava
 			guava

From 0996ae505a83fb452f17e6eb9f9382dfc0307fda Mon Sep 17 00:00:00 2001
From: dedece35 
Date: Wed, 9 Nov 2022 12:19:27 +0100
Subject: [PATCH 119/119] correction maven warn : dependency-plugin without
 version + delete useless 'java.version' block

---
 src/pom.xml | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/src/pom.xml b/src/pom.xml
index 7cf401cd8..40822e5c8 100644
--- a/src/pom.xml
+++ b/src/pom.xml
@@ -186,12 +186,8 @@
 			
 				
 					org.apache.maven.plugins
-					maven-compiler-plugin
-					3.10.1
-					
-						${java.version}
-						${java.version}
-					
+					maven-dependency-plugin
+					3.3.0