diff --git a/.github/workflows/stale_tag.yml b/.github/workflows/stale_tag.yml index 4c7a9ff96..0de6375dd 100644 --- a/.github/workflows/stale_tag.yml +++ b/.github/workflows/stale_tag.yml @@ -12,10 +12,10 @@ jobs: with: repo-token: ${{ secrets.GITHUB_TOKEN }} days-before-issue-stale: -1 # We don't want to address issues - days-before-pr-stale: 30 + days-before-pr-stale: 60 days-before-issue-close: -1 # We don't want to close issues in this action days-before-pr-close: -1 # We don't want to close PR in this action stale-pr-label: stale stale-pr-message: | - This PR has been automatically marked as stale because it has no activity for 30 days. - Please add a comment if you want to keep the issue open. Thank you for your contributions! \ No newline at end of file + This PR has been automatically marked as stale because it has no activity for 60 days. + Please add a comment if you want to keep the issue open. Thank you for your contributions! diff --git a/CHANGELOG.md b/CHANGELOG.md index 21415a0ef..c44062b79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,20 +7,49 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- [#248](https://github.com/green-code-initiative/ecoCode/issues/248) EC2 : Add tests to prove there is no problem with 'instanceof' operator + +### Changed + +### Deleted + +- [#4](https://github.com/green-code-initiative/ecoCode-python/issues/4) Deprecate rule EC66 for Python because not applicable (see details inside issue) +- [#258](https://github.com/green-code-initiative/ecoCode/pull/258) Deprecate rule EC63 for Java because there are already 3 native Sonarqube rules that cover the same use cases + +## [1.4.2] - 2023-12-05 + +### Added + +- [#224](https://github.com/green-code-initiative/ecoCode/issues/224) Add Swift rules from ecocode-ios to ecocode-rules-specifications + +### Changed + +- Update ecocode-rules-specifications to 0.0.9 + +### Deleted + +- [#243](https://github.com/green-code-initiative/ecoCode/pull/243) Deprecate rule EC4 for Java because not applicable + +## [1.4.1] - 2023-12-04 + ### Changed - [ios#3](https://github.com/green-code-initiative/ecoCode-ios/issues/3) Move iOS rules into centralized rules repository - [android#67](https://github.com/green-code-initiative/ecoCode-android/issues/67) Move Android rules into centralized rules repository -- [#216](https://github.com/green-code-initiative/ecoCode/issues/216) Upgrade rule EC2 for Java : Multiple if-else statement improvment +- [ios#3](https://github.com/green-code-initiative/ecoCode-ios/issues/3) Move iOS rules into centralized rules repository +- [#103](https://github.com/green-code-initiative/ecoCode/issues/103) Upgrade RULES.md: set proposed HTML rule "HTML page must contain a doctype tag" as refused with link to the justification - [#106](https://github.com/green-code-initiative/ecoCode/issues/106) Upgrade RULES.md : rule EC67 not relevant neither for Python nor Rust -- [#225](https://github.com/green-code-initiative/ecoCode/pull/225) Upgrade licence system and licence headers of Java files -- [#140](https://github.com/green-code-initiative/ecoCode/issues/140) Upgrade rule EC3 for Python : no implementation possible for python -- [#136](https://github.com/green-code-initiative/ecoCode/issues/136) Upgrade rule EC53 for Python : no implementation possible for python +- [#112](https://github.com/green-code-initiative/ecoCode/issues/112) Updating EC1 rule to add controls on streams - [#128](https://github.com/green-code-initiative/ecoCode/pull/128) Adding EC35 rule for Python and PHP : EC35 rule replaces EC34 with a specific use case ("file not found" sepcific) - [#132](https://github.com/green-code-initiative/ecoCode/issues/132) Upgrade RULES.md: set proposed Python rule "Use numpy array instead of standard list" as refused with link to the justification -- [#103](https://github.com/green-code-initiative/ecoCode/issues/103) Upgrade RULES.md: set proposed HTML rule "HTML page must contain a doctype tag" as refused with link to the justification - -### Deleted +- [#136](https://github.com/green-code-initiative/ecoCode/issues/136) Upgrade rule EC53 for Python : no implementation possible for python +- [#140](https://github.com/green-code-initiative/ecoCode/issues/140) Upgrade rule EC3 for Python : no implementation possible for python +- [#185](https://github.com/green-code-initiative/ecoCode/issues/185) Add build number to manifest +- [#216](https://github.com/green-code-initiative/ecoCode/issues/216) Upgrade rule EC2 for Java : Multiple if-else statement improvment +- [#225](https://github.com/green-code-initiative/ecoCode/pull/225) Upgrade licence system and licence headers of Java files +- [#247](https://github.com/green-code-initiative/ecoCode/issues/247) Upgrade rule EC2 for Java : float and double types deleted because of non compatibility with rule ## [1.4.0] - 2023-08-08 @@ -40,8 +69,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [#207](https://github.com/green-code-initiative/ecoCode/issues/207) Add release tag analyzis on SonarCloud -### Changed - ### Deleted - [#211](https://github.com/green-code-initiative/ecoCode/pull/211) Move JavaScript plugin to its dedicated repository @@ -174,7 +201,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - First official release of ecocode plugins : java plugin, php plugin and python plugin -[unreleased]: https://github.com/green-code-initiative/ecoCode/compare/v1.4.0...HEAD +[unreleased]: https://github.com/green-code-initiative/ecoCode/compare/v1.4.2...HEAD + +[1.4.2]: https://github.com/green-code-initiative/ecoCode/compare/v1.4.1...v1.4.2 + +[1.4.1]: https://github.com/green-code-initiative/ecoCode/compare/v1.4.0...v1.4.1 [1.4.0]: https://github.com/green-code-initiative/ecoCode/compare/v1.3.1...v1.4.0 diff --git a/RULES.md b/RULES.md index 8a023587f..6861531a2 100644 --- a/RULES.md +++ b/RULES.md @@ -11,57 +11,66 @@ Some are applicable for different technologies. - πŸš€ Rule to implement - 🚫 Non applicable rule -| Rule key | Name | Description | Reference/Validation | Java | Php | JS | Python | Rust | -|----------|------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------|-----|----|--------|------| -| | Use official social media sharing buttons | These JavaScript plugins are very resource-intensive: to work, they require a large number of requests and download heavy files. It is better to prefer direct links. | [cnumr best practices (3rd edition) BP_019](https://github.com/cnumr/best-practices/blob/main/chapters/BP_019_fr.md) | 🚫 | 🚫 | πŸš€ | 🚫 | 🚫 | -| | Non-grouped similar CSS declarations | When multiple Document Object Model (DOM) elements have common CSS properties, declare them together in the same style sheet. This method reduces the weight of CSS. | [cnumr best practices (3rd edition) BP_025](https://github.com/cnumr/best-practices/blob/main/chapters/BP_025_fr.md) | 🚫 | 🚫 | 🚧 | 🚫 | 🚫 | -| | CSS shorthand notations not used | Reduces the weight of the style sheet. | [cnumr best practices (3rd edition) BP_026](https://github.com/cnumr/best-practices/blob/main/chapters/BP_026_fr.md) | 🚫 | 🚫 | 🚫 | 🚫 | 🚫 | -| | CSS print not included | This style sheet reduces the number of pages printed. | [cnumr best practices (3rd edition) BP_027](https://github.com/cnumr/best-practices/blob/main/chapters/BP_027_fr.md) | 🚫 | 🚫 | 🚫 | 🚫 | 🚫 | -| | Non-standard fonts used | Prefer standard fonts, as they are already present on the user's computer, so they do not need to download them. This saves bandwidth, while speeding up the display of the site. | [cnumr best practices (3rd edition) BP_029](https://github.com/cnumr/best-practices/blob/main/chapters/BP_029_fr.md) | 🚫 | 🚫 | 🚫 | 🚫 | 🚫 | -| | Non-outsourced CSS and Javascript | If you include CSS or JavaScript code in the body of the HTML file, while the HTML file is used by several pages (or even the entire site), this code must be transferred for each page requested by the user, which increases the volume of data transmitted. | [cnumr best practices (3rd edition) BP_032](https://github.com/cnumr/best-practices/blob/main/chapters/BP_032_fr.md) | 🚫 | 🚫 | πŸš€ | 🚫 | 🚫 | -| | Resize images browser-side | Do not resize images using the HEIGHT and WIDTH attributes of the HTML code. This approach requires transferring these images to their original size, wasting bandwidth and CPU cycles. | [cnumr best practices (3rd edition) BP_034](https://github.com/cnumr/best-practices/blob/main/chapters/BP_034_fr.md) | 🚫 | 🚫 | 🚧 | 🚫 | 🚫 | -| EC10 | Use unoptimized vector images | Less heavy SVG images using less bandwidth | [cnumr best practices (3rd edition) BP_036](https://github.com/cnumr/best-practices/blob/main/chapters/BP_036_fr.md) | 🚧 | πŸš€ | πŸš€ | βœ… | πŸš€ | -| | Using too many CSS/javascript animations | JavaScript/CSS animations can be very expensive in terms of CPU cycles and memory consumption. | [cnumr best practices (3rd edition) BP_039](https://github.com/cnumr/best-practices/blob/main/chapters/BP_039_fr.md) | 🚫 | 🚫 | 🚧 | 🚫 | 🚫 | -| | Modify the DOM when traversing it | Modifying the DOM (Document Object Model) as you traverse it can lead to situations where the loop becomes very resource-intensive, especially CPU cycles. | [cnumr best practices (3rd edition) BP_041](https://github.com/cnumr/best-practices/blob/main/chapters/BP_041_fr.md) | 🚫 | 🚫 | 🚧 | 🚫 | 🚫 | -| | Edit DOM elements to make it invisible | When an element of the Document Object Model (DOM) needs to be modified by several properties, each change in style or content will generate a repaint or reflow. | [cnumr best practices (3rd edition) BP_042](https://github.com/cnumr/best-practices/blob/main/chapters/BP_042_fr.md) | 🚫 | 🚫 | πŸš€ | 🚫 | 🚫 | -| | Modify several CSS properties all at once | To limit the number of repaints/reflows, it is recommended not to modify properties one by one. (linter key : `@ecocode/no-multiple-style-changes`) | [cnumr best practices (3rd edition) BP_045](https://github.com/cnumr/best-practices/blob/main/chapters/BP_045_fr.md) | 🚫 | 🚫 | βœ… | 🚫 | 🚫 | -| EC34 | Using try...catch...finally calls (To be deleted becuse of new one EC35) | 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. That is why it is important not to use this construction and to prefer, as much as possible, a logical test. | [cnumr best practices (3rd edition) BP_047 (no longer exists in edition 4)](https://www.greenit.fr/2019/05/07/ecoconception-web-les-115-bonnes-pratiques-3eme-edition/) | πŸš€ | βœ… | πŸš€ | βœ… | πŸš€ | -| EC35 | Using try...catch calls (on File Not Found Exception) | 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. That is why it is important not to use this construction and to prefer, as much as possible, a logical test. This new rule replace old EC34 only for a particular use case (FileNotFoundException) | [cnumr best practices (3rd edition) BP_047 (no longer exists in edition 4)](https://www.greenit.fr/2019/05/07/ecoconception-web-les-115-bonnes-pratiques-3eme-edition/) | πŸš€ | βœ… | πŸš€ | βœ… | πŸš€ | -| EC22 | The use of methods for basic operations | Using methods for basic operations consumes additional system resources. The interpreter must in effect and solve the objects and then the methods, just to carry out these simple operations of the language. | [cnumr best practices (3rd edition) BP_048 (no longer exists in edition 4)](https://www.greenit.fr/2019/05/07/ecoconception-web-les-115-bonnes-pratiques-3eme-edition/) | πŸš€ | βœ… | πŸš€ | πŸš€ | πŸš€ | -| ??? | Call a DOM element multiple times without caching (linter key : `@ecocode/no-multiple-access-dom-element`) | Access to the Document Object Model (DOM) is costly in terms of CPU resources (CPU cycles). Also, when you use the same DOM element from JavaScript multiple times, store its reference in a variable so that you do not go through the DOM again for the same element. | [cnumr best practices (3rd edition) BP_049](https://github.com/cnumr/best-practices/blob/main/chapters/BP_049_fr.md) | 🚫 | 🚫 | βœ… | 🚫 | 🚫 | -| EC4 | Use global variables | When using a global variable, the interpretation engine must check: 1) that it exists in the current scope, in the one above, etc. ; 2) the variable has a value; 3) ... To avoid all these checks, it is often possible to pass the useful variables as arguments of routines, making them local. This process saves computational time (CPU cycles). | [cnumr best practices (3rd edition) BP_050 (no longer exists in edition 4)](https://www.greenit.fr/2019/05/07/ecoconception-web-les-115-bonnes-pratiques-3eme-edition/) | βœ… | βœ… | πŸš€ | βœ… | πŸš€ | -| EC53 | Using arrays in foreach loops | foreach deduplicates items in a list before starting the enumeration. It is therefore generally more economical to use a simple for loop when you have a good command of the collection. | [cnumr best practices (3rd edition) BP_053 (no longer exists in edition 4)](https://www.greenit.fr/2019/05/07/ecoconception-web-les-115-bonnes-pratiques-3eme-edition/) | βœ… | πŸš€ | πŸš€ | 🚫 | πŸš€ | -| EC7 | Rewrite native getter/setters | Overloading them lengthens the compilation and execution times of these methods, which are usually much better optimized by the language than by the developer. | [cnumr best practices (3rd edition) BP_062 (no longer exists in edition 4)](https://www.greenit.fr/2019/05/07/ecoconception-web-les-115-bonnes-pratiques-3eme-edition/) | πŸš€ | πŸš€ | πŸš€ | βœ… | πŸš€ | -| EC63 | Unnecessarily assigning values to variables | Avoid declaring and using variables when it is not indis-thinkable. Indeed, each allocation corresponds to the RAM occupied. | [cnumr best practices (3rd edition) BP_063 (no longer exists in edition 4)](https://www.greenit.fr/2019/05/07/ecoconception-web-les-115-bonnes-pratiques-3eme-edition/) | βœ… | πŸš€ | πŸš€ | πŸš€ | πŸš€ | +| Rule key | Name | Description | Reference/Validation | Java | Php | JS | Python | Rust | +|----------|------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------|-----|----|--------------------------------------------------------------------------------|------| +| | Use official social media sharing buttons | These JavaScript plugins are very resource-intensive: to work, they require a large number of requests and download heavy files. It is better to prefer direct links. | [cnumr best practices (3rd edition) BP_019](https://github.com/cnumr/best-practices/blob/main/chapters/BP_019_fr.md) | 🚫 | 🚫 | πŸš€ | 🚫 | 🚫 | +| | Non-grouped similar CSS declarations | When multiple Document Object Model (DOM) elements have common CSS properties, declare them together in the same style sheet. This method reduces the weight of CSS. | [cnumr best practices (3rd edition) BP_025](https://github.com/cnumr/best-practices/blob/main/chapters/BP_025_fr.md) | 🚫 | 🚫 | 🚧 | 🚫 | 🚫 | +| | CSS shorthand notations not used | Reduces the weight of the style sheet. | [cnumr best practices (3rd edition) BP_026](https://github.com/cnumr/best-practices/blob/main/chapters/BP_026_fr.md) | 🚫 | 🚫 | 🚫 | 🚫 | 🚫 | +| | CSS print not included | This style sheet reduces the number of pages printed. | [cnumr best practices (3rd edition) BP_027](https://github.com/cnumr/best-practices/blob/main/chapters/BP_027_fr.md) | 🚫 | 🚫 | 🚫 | 🚫 | 🚫 | +| | Non-standard fonts used | Prefer standard fonts, as they are already present on the user's computer, so they do not need to download them. This saves bandwidth, while speeding up the display of the site. | [cnumr best practices (3rd edition) BP_029](https://github.com/cnumr/best-practices/blob/main/chapters/BP_029_fr.md) | 🚫 | 🚫 | 🚫 | 🚫 | 🚫 | +| | Non-outsourced CSS and Javascript | If you include CSS or JavaScript code in the body of the HTML file, while the HTML file is used by several pages (or even the entire site), this code must be transferred for each page requested by the user, which increases the volume of data transmitted. | [cnumr best practices (3rd edition) BP_032](https://github.com/cnumr/best-practices/blob/main/chapters/BP_032_fr.md) | 🚫 | 🚫 | πŸš€ | 🚫 | 🚫 | +| | Resize images browser-side | Do not resize images using the HEIGHT and WIDTH attributes of the HTML code. This approach requires transferring these images to their original size, wasting bandwidth and CPU cycles. | [cnumr best practices (3rd edition) BP_034](https://github.com/cnumr/best-practices/blob/main/chapters/BP_034_fr.md) | 🚫 | 🚫 | 🚧 | 🚫 | 🚫 | +| EC10 | Use unoptimized vector images | Less heavy SVG images using less bandwidth | [cnumr best practices (3rd edition) BP_036](https://github.com/cnumr/best-practices/blob/main/chapters/BP_036_fr.md) | 🚧 | πŸš€ | πŸš€ | βœ… | πŸš€ | +| | Using too many CSS/javascript animations | JavaScript/CSS animations can be very expensive in terms of CPU cycles and memory consumption. | [cnumr best practices (3rd edition) BP_039](https://github.com/cnumr/best-practices/blob/main/chapters/BP_039_fr.md) | 🚫 | 🚫 | 🚧 | 🚫 | 🚫 | +| | Modify the DOM when traversing it | Modifying the DOM (Document Object Model) as you traverse it can lead to situations where the loop becomes very resource-intensive, especially CPU cycles. | [cnumr best practices (3rd edition) BP_041](https://github.com/cnumr/best-practices/blob/main/chapters/BP_041_fr.md) | 🚫 | 🚫 | 🚧 | 🚫 | 🚫 | +| | Edit DOM elements to make it invisible | When an element of the Document Object Model (DOM) needs to be modified by several properties, each change in style or content will generate a repaint or reflow. | [cnumr best practices (3rd edition) BP_042](https://github.com/cnumr/best-practices/blob/main/chapters/BP_042_fr.md) | 🚫 | 🚫 | πŸš€ | 🚫 | 🚫 | +| | Modify several CSS properties all at once | To limit the number of repaints/reflows, it is recommended not to modify properties one by one. (linter key : `@ecocode/no-multiple-style-changes`) | [cnumr best practices (3rd edition) BP_045](https://github.com/cnumr/best-practices/blob/main/chapters/BP_045_fr.md) | 🚫 | 🚫 | βœ… | 🚫 | 🚫 | +| EC34 | Using try...catch...finally calls (To be deleted becuse of new one EC35) | 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. That is why it is important not to use this construction and to prefer, as much as possible, a logical test. | [cnumr best practices (3rd edition) BP_047 (no longer exists in edition 4)](https://www.greenit.fr/2019/05/07/ecoconception-web-les-115-bonnes-pratiques-3eme-edition/) | 🚫 | βœ… | πŸš€ | βœ… | πŸš€ | +| EC35 | Using try...catch calls (on File Not Found Exception) | 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. That is why it is important not to use this construction and to prefer, as much as possible, a logical test. This new rule replace old EC34 only for a particular use case (FileNotFoundException) | [cnumr best practices (3rd edition) BP_047 (no longer exists in edition 4)](https://www.greenit.fr/2019/05/07/ecoconception-web-les-115-bonnes-pratiques-3eme-edition/) | 🚫 | 🚧 | πŸš€ | βœ… | πŸš€ | +| EC22 | The use of methods for basic operations | Using methods for basic operations consumes additional system resources. The interpreter must in effect and solve the objects and then the methods, just to carry out these simple operations of the language. | [cnumr best practices (3rd edition) BP_048 (no longer exists in edition 4)](https://www.greenit.fr/2019/05/07/ecoconception-web-les-115-bonnes-pratiques-3eme-edition/) | πŸš€ | βœ… | πŸš€ | πŸš€ | πŸš€ | +| ??? | Call a DOM element multiple times without caching (linter key : `@ecocode/no-multiple-access-dom-element`) | Access to the Document Object Model (DOM) is costly in terms of CPU resources (CPU cycles). Also, when you use the same DOM element from JavaScript multiple times, store its reference in a variable so that you do not go through the DOM again for the same element. | [cnumr best practices (3rd edition) BP_049](https://github.com/cnumr/best-practices/blob/main/chapters/BP_049_fr.md) | 🚫 | 🚫 | βœ… | 🚫 | 🚫 | +| EC4 | Use global variables | When using a global variable, the interpretation engine must check: 1) that it exists in the current scope, in the one above, etc. ; 2) the variable has a value; 3) ... To avoid all these checks, it is often possible to pass the useful variables as arguments of routines, making them local. This process saves computational time (CPU cycles). | [cnumr best practices (3rd edition) BP_050 (no longer exists in edition 4)](https://www.greenit.fr/2019/05/07/ecoconception-web-les-115-bonnes-pratiques-3eme-edition/) | 🚫 | βœ… | πŸš€ | βœ… | πŸš€ | +| EC53 | Using arrays in foreach loops | foreach deduplicates items in a list before starting the enumeration. It is therefore generally more economical to use a simple for loop when you have a good command of the collection. | [cnumr best practices (3rd edition) BP_053 (no longer exists in edition 4)](https://www.greenit.fr/2019/05/07/ecoconception-web-les-115-bonnes-pratiques-3eme-edition/) | βœ… | πŸš€ | πŸš€ | 🚫 | πŸš€ | +| EC7 | Rewrite native getter/setters | Overloading them lengthens the compilation and execution times of these methods, which are usually much better optimized by the language than by the developer. | [cnumr best practices (3rd edition) BP_062 (no longer exists in edition 4)](https://www.greenit.fr/2019/05/07/ecoconception-web-les-115-bonnes-pratiques-3eme-edition/) | πŸš€ | πŸš€ | πŸš€ | βœ… | πŸš€ | | EC66 | Use single quote (') instead of quotation mark (") | The shape using the quotation marks allows the developer to insert variables that will be substituted at run time. But if the string does not have a variable, use quotes instead. Thus, language will not look for variables to subtituture, which will reduce the consumption of CPU cycles. | [cnumr best practices (3rd edition) BP_066 (no longer exists in edition 4)](https://www.greenit.fr/2019/05/07/ecoconception-web-les-115-bonnes-pratiques-3eme-edition/) | πŸš€ | βœ… | πŸš€ | 🚫
[see](https://github.com/green-code-initiative/ecoCode-python/issues/4) | πŸš€ | -| EC67 | Use the $i++ variable during an iteration | The $i++ form has the disadvantage of generating a tem-porary variable during incrementation, which is not the case with the ++$i form. | [cnumr best practices (3rd edition) BP_067 (no longer exists in edition 4)](https://www.greenit.fr/2019/05/07/ecoconception-web-les-115-bonnes-pratiques-3eme-edition/) | βœ… | βœ… | πŸš€ | 🚫 | 🚫 | -| EC69 | Calling a function in the declaration of a for loop | Avoid calling the function each time the loop is iterated. | [cnumr best practices (3rd edition) BP_069 (no longer exists in edition 4)](https://www.greenit.fr/2019/05/07/ecoconception-web-les-115-bonnes-pratiques-3eme-edition/) | βœ… | βœ… | πŸš€ | βœ… | πŸš€ | -| EC72 | Perform an SQL query inside a loop | Servers are optimized to process multiple selections, insertions, or changes in a single query or transaction. consume CPU cycles, RAM, and bandwidth unnecessarily. | [cnumr best practices (3rd edition) BP_072](https://github.com/cnumr/best-practices/blob/main/chapters/BP_072_fr.md) | βœ… | βœ… | πŸš€ | βœ… | πŸš€ | -| EC74 | Write SELECT * FROM | The database server must resolve the fields based on the schema. If you are familiar with the diagram, it is strongly recommended to name the fields. | [cnumr best practices (3rd edition) BP_074 (no longer exists in edition 4)](https://www.greenit.fr/2019/05/07/ecoconception-web-les-115-bonnes-pratiques-3eme-edition/) | βœ… | βœ… | πŸš€ | βœ… | πŸš€ | -| EC1 | Calling a Spring repository inside a loop | The use of Spring repository in a loop induces unnecessary calculations by the CPU and therefore superfluous energy consumption. | | βœ… | 🚫 | 🚫 | 🚫 | 🚫 | -| EC3 | Getting the size of the collection in the loop | When iterating over any collection, fetch the size of the collection in advance to avoid fetching it on each iteration, this saves CPU cycles, and therefore consumes less power. | | βœ… | βœ… | πŸš€ | 🚫 | πŸš€ | -| EC2 | Multiple if-else statement | Using too many conditional if-else statements will impact performance since JVM will have to compare the conditions. Prefer using a switch statement instead of multiple if-else if possible, or refactor your code to reduce conditonnal statements on the same variable. Switch statement has a performance advantage over if – else. | | βœ… | βœ… | πŸš€ | 🚧 | πŸš€ | -| EC76 | Usage of static collections | 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. | | βœ… | 🚫 | 🚫 | 🚫 | 🚫 | -| EC77 | Usage Pattern.compile() in a non-static context | 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. | | βœ… | 🚫 | 🚫 | 🚫 | 🚫 | -| EC75 | Concatenate Strings in loop | 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. | | βœ… | 🚫 | 🚫 | 🚫 | 🚫 | -| EC78 | Const parameter in batch update | Don't set const parameter in batch update => Put its in query. Creating this parameter and destroying it consumes CPU cycles and RAM unnecessarily. | | βœ… | 🚫 | 🚫 | 🚫 | 🚫 | -| EC79 | Free resources | try-with-resources Statement needs to be implemented for any object that implements the AutoCloseable interface, it save computer resources. | | βœ… | 🚫 | 🚫 | 🚫 | 🚫 | -| EC32 | Initialize builder/buffer with the appropriate size | 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. This saves CPU cycles and therefore consumes less energy. | | βœ… | 🚫 | 🚫 | 🚫 | 🚫 | -| EC28 | Optimize read file exceptions | | | βœ… | 🚫 | 🚫 | 🚫 | 🚫 | -| EC5 | Usage of preparedStatement instead of Statement | SQL will only commit the query once, whereas if you used only one statement, it would commit the query every time and thus induce unnecessary calculations by the CPU and therefore superfluous energy consumption. | | βœ… | 🚫 | 🚫 | 🚫 | 🚫 | -| EC27 | Usage of system.arraycopy to copy arrays | 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. | | βœ… | 🚫 | 🚫 | 🚫 | 🚫 | -| EC404 | Avoid list comprehension in iterations | Use generator comprehension instead of list comprehension in for loop declaration | | 🚫 | 🚫 | 🚫 | βœ… | 🚫 | -| EC203 | Detect unoptimized file formats | When it is possible, to use svg format image over other image format | | πŸš€ | πŸš€ | πŸš€ | βœ… | πŸš€ | -| | Avoid high accuracy geolocation | Avoid using high accuracy geolocation in web applications (linter key : `@ecocode/avoid-high-accuracy-geolocation`) | | 🚫 | 🚫 | βœ… | 🚫 | 🚫 | -| | No import all from library | Should not import all from library (linter key : `@ecocode/no-import-all-from-library`) | | 🚫 | 🚫 | βœ… | 🚫 | 🚫 | -| | Prefer collections with pagination | Prefer API collections with pagination (linter key : `@ecocode/prefer-collections-with-pagination`) | | 🚫 | 🚫 | βœ… | 🚫 | 🚫 | +| EC67 | Use the $i++ variable during an iteration | The $i++ form has the disadvantage of generating a tem-porary variable during incrementation, which is not the case with the ++$i form. | [cnumr best practices (3rd edition) BP_067 (no longer exists in edition 4)](https://www.greenit.fr/2019/05/07/ecoconception-web-les-115-bonnes-pratiques-3eme-edition/) | βœ… | βœ… | πŸš€ | 🚫 | 🚫 | +| EC69 | Calling a function in the declaration of a for loop | Avoid calling the function each time the loop is iterated. | [cnumr best practices (3rd edition) BP_069 (no longer exists in edition 4)](https://www.greenit.fr/2019/05/07/ecoconception-web-les-115-bonnes-pratiques-3eme-edition/) | βœ… | βœ… | πŸš€ | βœ… | πŸš€ | +| EC72 | Perform an SQL query inside a loop | Servers are optimized to process multiple selections, insertions, or changes in a single query or transaction. consume CPU cycles, RAM, and bandwidth unnecessarily. | [cnumr best practices (3rd edition) BP_072](https://github.com/cnumr/best-practices/blob/main/chapters/BP_072_fr.md) | βœ… | βœ… | πŸš€ | βœ… | πŸš€ | +| EC74 | Write SELECT * FROM | The database server must resolve the fields based on the schema. If you are familiar with the diagram, it is strongly recommended to name the fields. | [cnumr best practices (3rd edition) BP_074 (no longer exists in edition 4)](https://www.greenit.fr/2019/05/07/ecoconception-web-les-115-bonnes-pratiques-3eme-edition/) | βœ… | βœ… | πŸš€ | βœ… | πŸš€ | +| EC1 | Calling a Spring repository inside a loop or a stream | The use of Spring repository in a loop or a stream induces unnecessary calculations by the CPU and therefore superfluous energy consumption. | | βœ… | 🚫 | 🚫 | 🚫 | 🚫 | +| EC3 | Getting the size of the collection in the loop | When iterating over any collection, fetch the size of the collection in advance to avoid fetching it on each iteration, this saves CPU cycles, and therefore consumes less power. | | βœ… | βœ… | πŸš€ | 🚫 | πŸš€ | +| EC2 | Multiple if-else statement | Using too many conditional if-else statements will impact performance since JVM will have to compare the conditions. Prefer using a switch statement instead of multiple if-else if possible, or refactor your code to reduce conditonnal statements on the same variable. Switch statement has a performance advantage over if – else. | | βœ… | βœ… | πŸš€ | 🚧 | πŸš€ | +| EC76 | Usage of static collections | 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. | | βœ… | 🚫 | 🚫 | 🚫 | 🚫 | +| EC77 | Usage Pattern.compile() in a non-static context | 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. | | βœ… | 🚫 | 🚫 | 🚫 | 🚫 | +| EC75 | Concatenate Strings in loop | 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. | | βœ… | 🚫 | 🚫 | 🚫 | 🚫 | +| EC78 | Const parameter in batch update | Don't set const parameter in batch update => Put its in query. Creating this parameter and destroying it consumes CPU cycles and RAM unnecessarily. | | βœ… | 🚫 | 🚫 | 🚫 | 🚫 | +| EC79 | Free resources | try-with-resources Statement needs to be implemented for any object that implements the AutoCloseable interface, it save computer resources. | | βœ… | 🚫 | 🚫 | 🚫 | 🚫 | +| EC32 | Initialize builder/buffer with the appropriate size | 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. This saves CPU cycles and therefore consumes less energy. | | βœ… | 🚫 | 🚫 | 🚫 | 🚫 | +| EC28 | Optimize read file exceptions | | | βœ… | 🚫 | 🚫 | 🚫 | 🚫 | +| EC5 | Usage of preparedStatement instead of Statement | SQL will only commit the query once, whereas if you used only one statement, it would commit the query every time and thus induce unnecessary calculations by the CPU and therefore superfluous energy consumption. | | βœ… | 🚫 | 🚫 | 🚫 | 🚫 | +| EC27 | Usage of system.arraycopy to copy arrays | 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. | | βœ… | 🚫 | 🚫 | 🚫 | 🚫 | +| EC404 | Avoid list comprehension in iterations | Use generator comprehension instead of list comprehension in for loop declaration | | 🚫 | 🚫 | 🚫 | βœ… | 🚫 | +| EC203 | Detect unoptimized file formats | When it is possible, to use svg format image over other image format | | πŸš€ | πŸš€ | πŸš€ | βœ… | πŸš€ | +| | Avoid high accuracy geolocation | Avoid using high accuracy geolocation in web applications (linter key : `@ecocode/avoid-high-accuracy-geolocation`) | | 🚫 | 🚫 | βœ… | 🚫 | 🚫 | +| | No import all from library | Should not import all from library (linter key : `@ecocode/no-import-all-from-library`) | | 🚫 | 🚫 | βœ… | 🚫 | 🚫 | +| | Prefer collections with pagination | Prefer API collections with pagination (linter key : `@ecocode/prefer-collections-with-pagination`) | | 🚫 | 🚫 | βœ… | 🚫 | 🚫 | +## Deprecated rules -## Refused rules +This table lists rules proposed by the community but deprecated in ecoCode plugins with the justification. These rules will be completely deleted in next releases and moved to bottom deleted rules array. -This table lists rules proposed by the community but refused in ecoCode plugins with the justification. +| Rule key | Language | Name | Description | Invalidation | +|----------|---------------------|----------------------------------------------------|----------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| EC4 | Java | Avoid using global variables | Global variables do not exist in Java. | [Github discussion with sources](https://github.com/green-code-initiative/ecoCode/issues/233) | +| EC34 | Java / Python / PHP | Using try...catch...finally calls | Implementation is too simple (only detection of presence of "try" statement) AND replaced by `EC35` rule | Github discussion with measures : [general/java](https://github.com/green-code-initiative/ecoCode/pull/128) / [python](https://github.com/green-code-initiative/ecoCode-python/pull/6) / [php](https://github.com/green-code-initiative/ecoCode-php/pull/10) | +| EC63 | Java | Unnecessarily assigning values to variables | There are already 3 native SonarQube rules for Java. | [Github discussion with sources](https://github.com/green-code-initiative/ecoCode/pull/258) | +| EC66 | Python | Use single quote (') instead of quotation mark (") | Finally, not applicable for Python | [Github discussion with sources](https://github.com/green-code-initiative/ecoCode-python/issues/4) | -| Language | Name | Description | Invalidation | -|----------|------------------------------------------|------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------| -| Python | Use numpy array instead of standard list | The use of numpy library to perform array manipulation is more energy efficient than the use of the standard list functions. | [Github discussion with measures](https://github.com/green-code-initiative/ecoCode/issues/132) | -| HTML | HTML page must contain a doctype tag | The difference in performance is negligible, this rule is more related to the user experience. | [Github discussion with sources](https://github.com/green-code-initiative/ecoCode/issues/103) | +## Refused / Deleted rules + +This table lists rules proposed by the community but refused or/and deleted in ecoCode plugins with the justification. + +| Rule key | Language | Name | Description | Invalidation | +|----------|----------|------------------------------------------|------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------| +| CRDOM203 | HTML | HTML page must contain a doctype tag | The difference in performance is negligible, this rule is more related to the user experience. | [Github discussion with sources](https://github.com/green-code-initiative/ecoCode/issues/103) | +| CRPYT | Python | Use numpy array instead of standard list | The use of numpy library to perform array manipulation is more energy efficient than the use of the standard list functions. | [Github discussion with measures](https://github.com/green-code-initiative/ecoCode/issues/132) | \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 27c21ce3e..df88e4b21 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -16,8 +16,8 @@ services: SONAR_ES_BOOTSTRAP_CHECKS_DISABLE: 'true' volumes: - type: bind - source: ./java-plugin/target/ecocode-java-plugin-1.4.1-SNAPSHOT.jar - target: /opt/sonarqube/extensions/plugins/ecocode-java-plugin-1.4.1-SNAPSHOT.jar + source: ./java-plugin/target/ecocode-java-plugin-1.4.3-SNAPSHOT.jar + target: /opt/sonarqube/extensions/plugins/ecocode-java-plugin-1.4.3-SNAPSHOT.jar - "extensions:/opt/sonarqube/extensions" - "logs:/opt/sonarqube/logs" - "data:/opt/sonarqube/data" diff --git a/ecocode-rules-specifications/README.md b/ecocode-rules-specifications/README.md index 1ee24ba52..b93d93d74 100644 --- a/ecocode-rules-specifications/README.md +++ b/ecocode-rules-specifications/README.md @@ -1,15 +1,45 @@ # ecoCode rules specification repository -## Description +This project contains the specifications of all ecoCode rules, for all languages. -This project contains the specifications of the ecoCode rules. +## Structure -All the existing rules can be found in the [rules folder](src/main/rules). +Rules are organized by folder based on their ID in the [root rules folder](src/main/rules). +Each of these folders contains a file with the metadata of the rule, and description by language. + +The metadata file uses the format supported by +the [SonarSource Analyzers Commons](https://github.com/SonarSource/sonar-analyzer-commons/tree/master/commons) library. +To find out what values can be put there, we advise you to use the +official [SonarQube documentation](https://docs.sonarsource.com/sonarqube/latest/user-guide/rules/overview/), and to +rely on already existing files. + +Here is an example: + +```text +src/main/rules +β”œβ”€β”€ EC104 +β”‚ β”œβ”€β”€ java +β”‚ β”‚ β”œβ”€β”€ EC104.asciidoc +β”‚ β”‚ β”œβ”€β”€ EC104.json +β”‚ β”œβ”€β”€ php +β”‚ β”‚ β”œβ”€β”€ EC104.asciidoc +β”‚ β”œβ”€β”€ python +β”‚ β”‚ β”œβ”€β”€ EC104.asciidoc +β”‚ └── EC104.json +β”œβ”€β”€ ... +``` + +To specify metadata for a given language (for example deprecate a rule only for a single language), it is possible to +create a json file in the language folder, and this will be merged with the common file during build. The keys in the +specific file have priority and it is possible to add new ones but not to delete them from the global one. ## Description language -The description of the rules uses the ASCIIDOC format (with [Markdown compatibility](https://docs.asciidoctor.org/asciidoc/latest/syntax-quick-reference/#markdown-compatibility)) in order to allow the inclusion of other pages (this feature is not available in standard with Markdown). +The description of the rules uses the ASCIIDOC format ( +with [Markdown compatibility](https://docs.asciidoctor.org/asciidoc/latest/syntax-quick-reference/#markdown-compatibility)) +in order to allow the inclusion of other pages (this feature is not available in standard with Markdown). See: + * [AsciiDoc Syntax Quick Reference](https://docs.asciidoctor.org/asciidoc/latest/syntax-quick-reference/) * [Compare AsciiDoc to Markdown](https://docs.asciidoctor.org/asciidoc/latest/asciidoc-vs-markdown/) diff --git a/ecocode-rules-specifications/pom.xml b/ecocode-rules-specifications/pom.xml index 5811cddb5..027f9d682 100644 --- a/ecocode-rules-specifications/pom.xml +++ b/ecocode-rules-specifications/pom.xml @@ -5,7 +5,7 @@ io.ecocode ecocode-parent - 1.4.1-SNAPSHOT + 1.4.3-SNAPSHOT ecocode-rules-specifications @@ -83,6 +83,21 @@ + + + + jakarta.json + jakarta.json-api + 2.1.2 + + + + org.glassfish + jakarta.json + 2.0.1 + module + + ---- -Examples of **compliant** code for this rule: +In your HTML file, you can include a link to the print stylesheet inside the section. +Use the media attribute with a value of "print" to indicate that this stylesheet is specifically for print. -[source,html] +[source,html,data-diff-id="3",data-diff-type="compliant"] ---- Web Page - + ---- -[source,html] +You can also use the @media print rule to define styles that should be applied when the page is printed. +Adjust font sizes, hide unnecessary elements, or make any other modifications suitable for print. + +[source,html,data-diff-id="4",data-diff-type="compliant"] ---- Web Page ---- -== Further details +== Resources + +=== Documentation + +- https://github.com/cnumr/best-practices/blob/main/chapters/BP_027_en.md[CNUMR best practices] - Provide a print CSS + +=== Articles & blog posts -This recommendation is made by the CNUMR: https://github.com/cnumr/best-practices/blob/main/chapters/BP_027_en.md[Provide a print CSS] +- https://www.sitepoint.com/css-printer-friendly-pages/[How to Create Printer-friendly Pages with CSS] diff --git a/ecocode-rules-specifications/src/main/rules/EC4/java/EC4.asciidoc b/ecocode-rules-specifications/src/main/rules/EC4/java/EC4.asciidoc index f8763b4ed..0aba43f63 100644 --- a/ecocode-rules-specifications/src/main/rules/EC4/java/EC4.asciidoc +++ b/ecocode-rules-specifications/src/main/rules/EC4/java/EC4.asciidoc @@ -1,18 +1,21 @@ -Prefer local variables as parameters +*This rule is deprecated because not applicable to Java, and will be removed soon.* + +== Why is this an issue? 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 status of local variables inside the function, thus saving computing time (CPU cycles). -## CASE 1 (Avoid as possible) +=== 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) +=== 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. -## Noncompliant Code Example +=== Noncompliant Code Example -```java +[source,java] +---- var aGlobal = new String('Hello'); function globalLength(){ @@ -21,11 +24,12 @@ function globalLength(){ } globalLength(); -``` +---- -## Compliant Solution +== Compliant Solution -```java +[source,java] +---- var aGlobal = new String('Hello'); function someVarLength(str){ @@ -34,4 +38,4 @@ function someVarLength(str){ } somVarLength(aGlobal); -``` +---- diff --git a/ecocode-rules-specifications/src/main/rules/EC4/java/EC4.json b/ecocode-rules-specifications/src/main/rules/EC4/java/EC4.json new file mode 100644 index 000000000..0b963543b --- /dev/null +++ b/ecocode-rules-specifications/src/main/rules/EC4/java/EC4.json @@ -0,0 +1,3 @@ +{ + "status": "deprecated" +} diff --git a/ecocode-rules-specifications/src/main/rules/EC63/java/EC63.asciidoc b/ecocode-rules-specifications/src/main/rules/EC63/java/EC63.asciidoc index 9d3ca796d..b5f7ea887 100644 --- a/ecocode-rules-specifications/src/main/rules/EC63/java/EC63.asciidoc +++ b/ecocode-rules-specifications/src/main/rules/EC63/java/EC63.asciidoc @@ -1,17 +1,23 @@ +*This rule is deprecated because there are already Sonarqube native rules for the same things, and will be removed soon.* + +== Why is this an issue? + Do not unnecessarily assign values to variables. It increases the use of RAM memory. -## Noncompliant Code Example +== Noncompliant Code Example -```java +[source,java] +---- String var1 = getValue(); return var1; String var2 = "hello" var2 = "world" //Non compliant cause never assigned -``` +---- -## Compliant Solution +== Compliant Solution -```java +[source,java] +---- return getValue(); -``` +---- diff --git a/ecocode-rules-specifications/src/main/rules/EC63/java/EC63.json b/ecocode-rules-specifications/src/main/rules/EC63/java/EC63.json new file mode 100644 index 000000000..0b963543b --- /dev/null +++ b/ecocode-rules-specifications/src/main/rules/EC63/java/EC63.json @@ -0,0 +1,3 @@ +{ + "status": "deprecated" +} diff --git a/ecocode-rules-specifications/src/main/rules/EC66/python/EC66.asciidoc b/ecocode-rules-specifications/src/main/rules/EC66/python/EC66.asciidoc index 09e0eda41..614eda9c2 100644 --- a/ecocode-rules-specifications/src/main/rules/EC66/python/EC66.asciidoc +++ b/ecocode-rules-specifications/src/main/rules/EC66/python/EC66.asciidoc @@ -1,12 +1,17 @@ +*This rule is deprecated because finally, not applicable for Python, and will be removed soon.* + +== Why is this an issue? + The shape using the quotation marks (") allows the developer to insert variables that will be substituted at run time. But if the string does not have a variable, use quotes (') instead. Thus, language will not look for variables to substitute, which will reduce the consumption of CPU cycles. -## Noncompliant Code Example +== Noncompliant Code Example -```python +[source,python] +---- # in variables firstname = "Andrea" # Noncompliant {{Avoid using quotation mark ("), prefer using simple quote (')}} @@ -15,11 +20,12 @@ def my_function(name, age): print(name + 'is' + age + ' yo.') my_function("Robert", 12) # Noncompliant {{Avoid using quotation mark ("), prefer using simple quote (')}} -``` +---- -## Compliant Solution +== Compliant Solution -```python +[source,python] +---- # in variables firstname = 'Andrea' @@ -28,4 +34,4 @@ def my_function(name, age): print(name + 'is' + age + ' yo.') my_function('Robert', 12) -``` +---- diff --git a/ecocode-rules-specifications/src/main/rules/EC66/python/EC66.json b/ecocode-rules-specifications/src/main/rules/EC66/python/EC66.json new file mode 100644 index 000000000..cf4002b76 --- /dev/null +++ b/ecocode-rules-specifications/src/main/rules/EC66/python/EC66.json @@ -0,0 +1,3 @@ +{ + "status": "deprecated" +} \ No newline at end of file diff --git a/ecocode-rules-specifications/src/main/rules/EC8/EC8.json b/ecocode-rules-specifications/src/main/rules/EC8/EC8.json index 63ce5394e..3d5e75650 100644 --- a/ecocode-rules-specifications/src/main/rules/EC8/EC8.json +++ b/ecocode-rules-specifications/src/main/rules/EC8/EC8.json @@ -1,6 +1,12 @@ { "title": "Avoid using high accuracy geolocation in web applications.", "type": "CODE_SMELL", + "code": { + "impacts": { + "MAINTAINABILITY": "MEDIUM" + }, + "attribute": "EFFICIENT" + }, "status": "ready", "remediation": { "func": "Constant\/Issue", diff --git a/ecocode-rules-specifications/src/main/rules/EC8/javascript/EC8.asciidoc b/ecocode-rules-specifications/src/main/rules/EC8/javascript/EC8.asciidoc index 10f331852..71b5146f0 100644 --- a/ecocode-rules-specifications/src/main/rules/EC8/javascript/EC8.asciidoc +++ b/ecocode-rules-specifications/src/main/rules/EC8/javascript/EC8.asciidoc @@ -1,44 +1,42 @@ -This rule aims at reducing CPU consumption by telling the device to use a less accurate yet more eco-friendly geolocation, when geolocation API is used. +:!sectids: -== Examples +== Why is this an issue? -Examples of **non-compliant** code for this rule: +High-precision geolocation typically requires more power from the device's GPS hardware. +By requesting less accurate geolocation, you can reduce the power consumption, leading to extended battery life, which is crucial for mobile devices. -[source,js] ----- -var options = { enableHighAccuracy: true, timeout: 5000, maximumAge: 0 }; -function success(pos) { - console.log(pos.coords); -} - -function error(err) { - console.warn(err); -} +Obtaining highly accurate geolocation often involves more complex calculations and processing, which can increase CPU usage. +If the application or service does not critically require pinpoint accuracy, opting for a less accurate geolocation can help minimize the strain on the device's CPU. -navigator.geolocation.getCurrentPosition(success, error, options); +[source,js,data-diff-id="1",data-diff-type="noncompliant"] +---- +var options = { enableHighAccuracy: true, timeout: 5000, maximumAge: 0 }; // Non-compliant +navigator.geolocation.getCurrentPosition( + (pos) => console.log(pos), + (err) => console.warn(err), + options +); ---- -Examples of **compliant** code for this rule: +In these examples, the enableHighAccuracy option is set to false (the default), indicating that the application prefers lower-accuracy geolocation to conserve resources: -[source,js] +[source,js,data-diff-id="1",data-diff-type="compliant"] ---- -// enableHighAccuracy is false by default, so not declaring it is correct -function success(pos) { - console.log(pos); -} -navigator.geolocation.getCurrentPosition(success); +navigator.geolocation.getCurrentPosition((pos) => console.log(pos)); // Compliant by default ---- -[source,js] +[source,js,data-diff-id="1",data-diff-type="compliant"] +---- +var options = { enableHighAccuracy: false, timeout: 5000, maximumAge: 0 }; // Compliant +navigator.geolocation.getCurrentPosition( + (pos) => console.log(pos), + (err) => console.warn(err), + options +); ---- -var options = { enableHighAccuracy: false, timeout: 5000, maximumAge: 0 }; -function success(pos) { - console.log(pos.coords); -} -function error(err) { - console.warn(err); -} +== Resources -navigator.geolocation.getCurrentPosition(success, error, options); ----- +=== Documentation + +- https://developer.mozilla.org/en-US/docs/Web/API/Geolocation/getCurrentPosition[Mozilla Web Technology for Developers] - getCurrentPosition() method diff --git a/ecocode-rules-specifications/src/main/rules/EC9/EC9.json b/ecocode-rules-specifications/src/main/rules/EC9/EC9.json index 78ca94bdf..c5dabd5e7 100644 --- a/ecocode-rules-specifications/src/main/rules/EC9/EC9.json +++ b/ecocode-rules-specifications/src/main/rules/EC9/EC9.json @@ -1,6 +1,12 @@ { "title": "Should not import all from library", "type": "CODE_SMELL", + "code": { + "impacts": { + "MAINTAINABILITY": "MEDIUM" + }, + "attribute": "EFFICIENT" + }, "status": "ready", "remediation": { "func": "Constant\/Issue", diff --git a/ecocode-rules-specifications/src/main/rules/EC9/javascript/EC9.asciidoc b/ecocode-rules-specifications/src/main/rules/EC9/javascript/EC9.asciidoc index cd0e2ec2a..14ac4b248 100644 --- a/ecocode-rules-specifications/src/main/rules/EC9/javascript/EC9.asciidoc +++ b/ecocode-rules-specifications/src/main/rules/EC9/javascript/EC9.asciidoc @@ -1,6 +1,13 @@ -This rule aims to reduce weight of programs by using only needed modules. -Many libraries export only one module by default, but some of them are exporting ES modules or submodules. -We should use them to select more precisly needed modules and avoid unnecessarily overloading files weight. +:!sectids: + +== Why is this an issue? + +Including only the required modules decreases the overall size of the program. +This, in turn, reduces the amount of memory and storage space needed to run and store the application. +This is especially critical in environments with limited resources, such as on mobile devices or in web applications where bandwidth and download times matter. + +Smaller programs generally have better runtime performance. +Reducing the number of unnecessary modules minimizes the amount of code that needs to be interpreted or compiled, leading to faster execution and improved overall performance. *Example with the well-known https://lodash.com/[lodash] library, if you only need `isEmpty` method.* @@ -23,29 +30,33 @@ a|index.js - 24.42 KB |=== -== Examples - -Examples of **non-compliant** code for this rule: - -[source,js] +[source,js,data-diff-id="2",data-diff-type="noncompliant"] ---- // Example with lodash -import lodash from "lodash"; -import { isEmpty } from "lodash"; -import * as lodash from "lodash"; +import lodash from "lodash"; // Non-compliant +import { isEmpty } from "lodash"; // Non-compliant +import * as lodash from "lodash"; // Non-compliant // Example with underscore -import _ from "underscore"; +import _ from "underscore"; // Non-compliant ---- -Examples of **compliant** code for this rule: - -[source,js] +[source,js,data-diff-id="2",data-diff-type="compliant"] ---- // Example with lodash (uses submodules) -import isEmpty from "lodash/isEmpty"; -import intersect from "lodash/intersect"; +import isEmpty from "lodash/isEmpty"; // Compliant +import intersect from "lodash/intersect"; // Compliant // Example with underscore (uses esm modules) -import map from "underscore/modules/map.js"; +import map from "underscore/modules/map.js"; // Compliant ---- + +== Resources + +=== Documentation + +- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import[Mozilla Web Technology for Developers] - import + +=== Articles & blog posts + +- https://dev.to/dianjuar/importing-modules-in-javascript-are-we-doing-it-right-nc[Importing modules in JavaScript, are we doing it right?] diff --git a/ecocode-rules-specifications/src/main/script/PrepareResources.jsh b/ecocode-rules-specifications/src/main/script/PrepareResources.jsh index 04f15b3f6..f65d4d92a 100644 --- a/ecocode-rules-specifications/src/main/script/PrepareResources.jsh +++ b/ecocode-rules-specifications/src/main/script/PrepareResources.jsh @@ -1,5 +1,13 @@ //usr/bin/env jshell -v "$@" "$0"; exit $? + +import jakarta.json.Json; +import jakarta.json.JsonMergePatch; +import jakarta.json.JsonObject; +import jakarta.json.JsonReader; +import jakarta.json.JsonValue; +import jakarta.json.JsonWriter; + import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -22,7 +30,7 @@ import static java.util.Optional.of; private final Path sourceDir; private final Path targetDir; - public static void main(String... args) throws Exception { + public static void main(String... args) { new PrepareResources( Path.of(Objects.requireNonNull(System.getProperty("sourceDir"), "system property: sourceDir")), Path.of(Objects.requireNonNull(System.getProperty("targetDir"), "system property: targetDir")) @@ -37,7 +45,7 @@ import static java.util.Optional.of; @Override public void run() { getResourcesToCopy().forEach(rule -> { - copyFile(rule.metadata, rule.getMetadataTargetPath(targetDir)); + mergeAndCopyJsonMetadata(rule.metadata, rule.specificMetadata, rule.getMetadataTargetPath(targetDir)); copyFile(rule.htmlDescription, rule.getHtmlDescriptionTargetPath(targetDir)); }); } @@ -55,6 +63,32 @@ import static java.util.Optional.of; } } + private void mergeAndCopyJsonMetadata(Path source, Path merge, Path target) { + if (Files.isRegularFile(merge)) { + LOGGER.log(DEBUG, "Merge: {0} and {1} -> {2}", source, merge, target); + + try ( + JsonReader sourceJsonReader = Json.createReader(Files.newBufferedReader(source)); + JsonReader mergeJsonReader = Json.createReader(Files.newBufferedReader(merge)); + JsonWriter resultJsonWriter = Json.createWriter(Files.newBufferedWriter(target)); + ) { + Files.createDirectories(target.getParent()); + + JsonObject sourceJson = sourceJsonReader.readObject(); + JsonObject mergeJson = mergeJsonReader.readObject(); + + JsonMergePatch mergePatch = Json.createMergePatch(mergeJson); + JsonValue result = mergePatch.apply(sourceJson); + + resultJsonWriter.write(result); + } catch (IOException e) { + throw new RuntimeException("cannot process source " + source, e); + } + } else { + copyFile(source, target); + } + } + private void copyFile(Path source, Path target) { LOGGER.log(DEBUG, "Copy: {0} -> {1}", source, target); try { @@ -79,6 +113,7 @@ import static java.util.Optional.of; } final String ruleKey = matcher.group("ruleKey"); final Path metadata = htmlDescription.getParent().getParent().resolve(ruleKey + ".json"); + final Path specificMetadata = htmlDescription.getParent().resolve(ruleKey + ".json"); if (!Files.isRegularFile(htmlDescription) || !Files.isRegularFile(metadata)) { return empty(); @@ -87,18 +122,21 @@ import static java.util.Optional.of; return of(new Rule( matcher.group("language"), htmlDescription, - metadata + metadata, + specificMetadata )); } private final String language; private final Path htmlDescription; private final Path metadata; + private final Path specificMetadata; - Rule(String language, Path htmlDescription, Path metadata) { + Rule(String language, Path htmlDescription, Path metadata, Path specificMetadata) { this.language = language; this.htmlDescription = htmlDescription; this.metadata = metadata; + this.specificMetadata = specificMetadata; } Path getHtmlDescriptionTargetPath(Path targetDir) { diff --git a/java-plugin/pom.xml b/java-plugin/pom.xml index 6f7424f31..cff0d022b 100644 --- a/java-plugin/pom.xml +++ b/java-plugin/pom.xml @@ -5,7 +5,7 @@ io.ecocode ecocode-parent - 1.4.1-SNAPSHOT + 1.4.3-SNAPSHOT ecocode-java-plugin @@ -18,7 +18,7 @@ - 0.0.6 + 0.0.9 @@ -89,11 +89,15 @@ true ecocodejava - ${project.name} fr.greencodeinitiative.java.JavaPlugin true - ${sonarqube.version} + ${sonarqube.version} ${java.version} + + + ${buildNumber} + + @@ -101,6 +105,24 @@ org.apache.maven.plugins maven-shade-plugin + + + org.codehaus.mojo + buildnumber-maven-plugin + 3.1.0 + + + validate + + create + + + + + true + 0 + + org.jacoco jacoco-maven-plugin diff --git a/java-plugin/src/main/java/fr/greencodeinitiative/java/JavaCheckRegistrar.java b/java-plugin/src/main/java/fr/greencodeinitiative/java/JavaCheckRegistrar.java index b66e81cfa..f972a2023 100644 --- a/java-plugin/src/main/java/fr/greencodeinitiative/java/JavaCheckRegistrar.java +++ b/java-plugin/src/main/java/fr/greencodeinitiative/java/JavaCheckRegistrar.java @@ -28,7 +28,7 @@ import fr.greencodeinitiative.java.checks.AvoidRegexPatternNotStatic; import fr.greencodeinitiative.java.checks.AvoidSQLRequestInLoop; import fr.greencodeinitiative.java.checks.AvoidSetConstantInBatchUpdate; -import fr.greencodeinitiative.java.checks.AvoidSpringRepositoryCallInLoopCheck; +import fr.greencodeinitiative.java.checks.AvoidSpringRepositoryCallInLoopOrStreamCheck; import fr.greencodeinitiative.java.checks.AvoidStatementForDMLQueries; import fr.greencodeinitiative.java.checks.AvoidUsageOfStaticCollections; import fr.greencodeinitiative.java.checks.AvoidUsingGlobalVariablesCheck; @@ -60,7 +60,7 @@ public class JavaCheckRegistrar implements CheckRegistrar { AvoidRegexPatternNotStatic.class, NoFunctionCallWhenDeclaringForLoop.class, AvoidStatementForDMLQueries.class, - AvoidSpringRepositoryCallInLoopCheck.class, + AvoidSpringRepositoryCallInLoopOrStreamCheck.class, AvoidSQLRequestInLoop.class, AvoidFullSQLRequest.class, UseCorrectForLoop.class, diff --git a/java-plugin/src/main/java/fr/greencodeinitiative/java/checks/AvoidMultipleIfElseStatement.java b/java-plugin/src/main/java/fr/greencodeinitiative/java/checks/AvoidMultipleIfElseStatement.java index 383365309..5b0afc42f 100644 --- a/java-plugin/src/main/java/fr/greencodeinitiative/java/checks/AvoidMultipleIfElseStatement.java +++ b/java-plugin/src/main/java/fr/greencodeinitiative/java/checks/AvoidMultipleIfElseStatement.java @@ -180,7 +180,9 @@ private void computeConditionVariables(BinaryExpressionTree pBinExprTree, int pL * @param pLevel the level of structure */ private void computeVariables(IdentifierTree pVarIdTree, int pLevel) { - if (pVarIdTree.is(Kind.IDENTIFIER)) { + if (pVarIdTree.is(Kind.IDENTIFIER) + && !pVarIdTree.symbolType().is("float") + && !pVarIdTree.symbolType().is("double")) { // increment the variable counter to list of all variables int nbUsed = variablesStruct.incrementVariableUsageForLevel(pVarIdTree.name(), pLevel); @@ -217,18 +219,21 @@ private void visitElseNode(BlockTree pElseTree, int pLevel) { */ private void computeElseVariables(StatementTree pElseTree, int pLevel) { - for (Map.Entry entry : variablesStruct.getVariablesForCurrentIfStruct(pLevel).entrySet()) { - String variableName = entry.getKey(); + Map mapVar = variablesStruct.getVariablesForCurrentIfStruct(pLevel); + if (mapVar != null) { + for (Map.Entry entry : mapVar.entrySet()) { + String variableName = entry.getKey(); - // increment usage of all variables in the same level of ELSE staetement - int nbUsed = variablesStruct.incrementVariableUsageForLevel(variableName, pLevel); + // increment usage of all variables in the same level of ELSE staetement + int nbUsed = variablesStruct.incrementVariableUsageForLevel(variableName, pLevel); - // increment variable counter to list of variables already declared for current if or elseif struture - variablesStruct.incrementVariableUsageForLevelForCurrentIfStruct(variableName, pLevel); + // increment variable counter to list of variables already declared for current if or elseif struture + variablesStruct.incrementVariableUsageForLevelForCurrentIfStruct(variableName, pLevel); - // raise an error if maximum - if (nbUsed > NB_MAX_VARIABLE_USAGE) { - reportIssue(pElseTree, ERROR_MESSAGE); + // raise an error if maximum + if (nbUsed > NB_MAX_VARIABLE_USAGE) { + reportIssue(pElseTree, ERROR_MESSAGE); + } } } } diff --git a/java-plugin/src/main/java/fr/greencodeinitiative/java/checks/AvoidSpringRepositoryCallInLoopCheck.java b/java-plugin/src/main/java/fr/greencodeinitiative/java/checks/AvoidSpringRepositoryCallInLoopCheck.java deleted file mode 100644 index e95d75e98..000000000 --- a/java-plugin/src/main/java/fr/greencodeinitiative/java/checks/AvoidSpringRepositoryCallInLoopCheck.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * ecoCode - Java language - Provides rules to reduce the environmental footprint of your Java programs - * Copyright Β© 2023 Green Code Initiative (https://www.ecocode.io) - * - * 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 . - */ -package fr.greencodeinitiative.java.checks; - -import java.util.Arrays; -import java.util.List; - -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; -import org.sonarsource.analyzer.commons.annotations.DeprecatedRuleKey; - -@Rule(key = "EC1") -@DeprecatedRuleKey(repositoryKey = "greencodeinitiative-java", ruleKey = "GRC1") -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/java-plugin/src/main/java/fr/greencodeinitiative/java/checks/AvoidSpringRepositoryCallInLoopOrStreamCheck.java b/java-plugin/src/main/java/fr/greencodeinitiative/java/checks/AvoidSpringRepositoryCallInLoopOrStreamCheck.java new file mode 100644 index 000000000..3222799ca --- /dev/null +++ b/java-plugin/src/main/java/fr/greencodeinitiative/java/checks/AvoidSpringRepositoryCallInLoopOrStreamCheck.java @@ -0,0 +1,123 @@ +/* + * ecoCode - Java language - Provides rules to reduce the environmental footprint of your Java programs + * Copyright Β© 2023 Green Code Initiative (https://www.ecocode.io) + * + * 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 . + */ +package fr.greencodeinitiative.java.checks; + +import java.util.Arrays; +import java.util.List; + +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.sonarsource.analyzer.commons.annotations.DeprecatedRuleKey; + +@Rule(key = "EC1") +@DeprecatedRuleKey(repositoryKey = "greencodeinitiative-java", ruleKey = "GRC1") +public class AvoidSpringRepositoryCallInLoopOrStreamCheck extends IssuableSubscriptionVisitor { + + protected static final String RULE_MESSAGE = "Avoid Spring repository call in loop or stream"; + + private static final String BASE_STREAM = "java.util.stream.BaseStream"; + private static final String SPRING_REPOSITORY = "org.springframework.data.repository.Repository"; + + private static final MethodMatchers SPRING_REPOSITORY_METHOD = + MethodMatchers + .create() + .ofSubTypes(SPRING_REPOSITORY) + .anyName() + .withAnyParameters() + .build(); + + private static final MethodMatchers STREAM_FOREACH_METHOD = + MethodMatchers + .create() + .ofSubTypes(BASE_STREAM) + .names("forEach", "forEachOrdered", "map", "peek") + .withAnyParameters() + .build(); + + private final AvoidSpringRepositoryCallInLoopCheckVisitor visitorInFile = new AvoidSpringRepositoryCallInLoopCheckVisitor(); + private final StreamVisitor streamVisitor = new StreamVisitor(); + + private final AncestorMethodVisitor ancestorMethodVisitor = new AncestorMethodVisitor(); + + @Override + public List nodesToVisit() { + return Arrays.asList( + Tree.Kind.FOR_EACH_STATEMENT, // loop + Tree.Kind.FOR_STATEMENT, // loop + Tree.Kind.WHILE_STATEMENT, // loop + Tree.Kind.DO_STATEMENT, // loop + Tree.Kind.METHOD_INVOCATION // stream + ); + } + + @Override + public void visitNode(Tree tree) { + if (tree.is(Tree.Kind.METHOD_INVOCATION)) { // stream process + MethodInvocationTree methodInvocationTree = (MethodInvocationTree) tree; + if (STREAM_FOREACH_METHOD.matches(methodInvocationTree)) { + tree.accept(streamVisitor); + } + } else { // loop process + tree.accept(visitorInFile); + } + } + + private class AvoidSpringRepositoryCallInLoopCheckVisitor extends BaseTreeVisitor { + @Override + public void visitMethodInvocation(MethodInvocationTree tree) { + if (SPRING_REPOSITORY_METHOD.matches(tree)) { + reportIssue(tree, RULE_MESSAGE); + } else { + super.visitMethodInvocation(tree); + } + } + + } + + private class StreamVisitor extends BaseTreeVisitor { + + @Override + public void visitLambdaExpression(LambdaExpressionTree tree) { + tree.accept(ancestorMethodVisitor); + } + + } + + private class AncestorMethodVisitor extends BaseTreeVisitor { + + @Override + public void visitMethodInvocation(MethodInvocationTree tree) { + // if the method is a spring repository method, report an issue + if (SPRING_REPOSITORY_METHOD.matches(tree)) { + reportIssue(tree, RULE_MESSAGE); + } else { // else, check if the method is a method invocation and check recursively + if (tree.methodSelect().is(Tree.Kind.MEMBER_SELECT)) { + MemberSelectExpressionTree memberSelectTree = (MemberSelectExpressionTree) tree.methodSelect(); + if ( memberSelectTree.expression().is(Tree.Kind.METHOD_INVOCATION)) { + MethodInvocationTree methodInvocationTree = (MethodInvocationTree) memberSelectTree.expression(); + methodInvocationTree.accept(ancestorMethodVisitor); + } + } + } + } + + } + +} diff --git a/java-plugin/src/main/java/fr/greencodeinitiative/java/checks/AvoidUsingGlobalVariablesCheck.java b/java-plugin/src/main/java/fr/greencodeinitiative/java/checks/AvoidUsingGlobalVariablesCheck.java index 98bb254b4..26a6dbddc 100644 --- a/java-plugin/src/main/java/fr/greencodeinitiative/java/checks/AvoidUsingGlobalVariablesCheck.java +++ b/java-plugin/src/main/java/fr/greencodeinitiative/java/checks/AvoidUsingGlobalVariablesCheck.java @@ -17,9 +17,6 @@ */ package fr.greencodeinitiative.java.checks; -import java.util.Arrays; -import java.util.List; - import com.google.re2j.Pattern; import org.sonar.check.Rule; import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; @@ -28,6 +25,15 @@ import org.sonar.plugins.java.api.tree.VariableTree; import org.sonarsource.analyzer.commons.annotations.DeprecatedRuleKey; +import java.util.Arrays; +import java.util.List; + +/** + * Check to avoid using global variables. + * + * @deprecated because not applicable to Java language, to be removed soon + */ +@Deprecated(forRemoval = true) @Rule(key = "EC4") @DeprecatedRuleKey(repositoryKey = "greencodeinitiative-java", ruleKey = "D4") public class AvoidUsingGlobalVariablesCheck extends IssuableSubscriptionVisitor { @@ -42,7 +48,6 @@ public List nodesToVisit() { @Override public void visitNode(Tree tree) { - if (tree.is(Kind.STATIC_INITIALIZER)) { reportIssue(tree, String.format(ERROR_MESSAGE, tree)); } @@ -57,4 +62,5 @@ public void visitNode(Tree tree) { } } } + } diff --git a/java-plugin/src/main/java/fr/greencodeinitiative/java/checks/UnnecessarilyAssignValuesToVariables.java b/java-plugin/src/main/java/fr/greencodeinitiative/java/checks/UnnecessarilyAssignValuesToVariables.java index f5544d2e5..aba735bff 100644 --- a/java-plugin/src/main/java/fr/greencodeinitiative/java/checks/UnnecessarilyAssignValuesToVariables.java +++ b/java-plugin/src/main/java/fr/greencodeinitiative/java/checks/UnnecessarilyAssignValuesToVariables.java @@ -27,6 +27,13 @@ import javax.annotation.CheckForNull; import java.util.*; +/** + * @deprecated not applicable because of existing Sonarqube native rules : + * - unused variable : https://rules.sonarsource.com/java/tag/unused/RSPEC-1481/ + * - useless assignment : https://rules.sonarsource.com/java/tag/unused/RSPEC-1854 + * - immediately return : https://rules.sonarsource.com/java/RSPEC-1488/ + */ +@Deprecated(forRemoval = true) @Rule(key = "EC63") @DeprecatedRuleKey(repositoryKey = "greencodeinitiative-java", ruleKey = "S63") public class UnnecessarilyAssignValuesToVariables extends BaseTreeVisitor implements JavaFileScanner { diff --git a/java-plugin/src/test/files/AvoidMultipleIfElseStatementNoIssue.java b/java-plugin/src/test/files/AvoidMultipleIfElseStatementNoIssue.java index a56e9e599..32f4716be 100644 --- a/java-plugin/src/test/files/AvoidMultipleIfElseStatementNoIssue.java +++ b/java-plugin/src/test/files/AvoidMultipleIfElseStatementNoIssue.java @@ -208,4 +208,67 @@ public int shouldBeCompliantBecauseSeveralVariablesUsedMaximumTwiceInIfOrElseIfS return nb2; } + // COMPLIANT + // USE CASE : Compliant use case to check if following is OK : + // - usage of the same variable on different levels of IF statements but with incompatible type for a switch + public float shouldBeCompliantBecauseVariableHasNotCompatibleTypeFloatForSwitch() + { + float nb1 = 0.0f; + + if (nb1 > 1) { + nb1 = 2.1f; + } else { + if (nb1 > 2) { + nb1 = 1.1f; + } + } + + return nb1; + } + + // COMPLIANT + // USE CASE : Compliant use case to check if following is OK : + // - usage of the same variable on different levels of IF statements but with incompatible type for a switch + public double shouldBeCompliantBecauseVariableHasNotCompatibleTypeDoubleForSwitch() + { + double nb1 = 0.0; + + if (nb1 > 1) { + nb1 = 2.1; + } else { + if (nb1 > 2) { + nb1 = 1.1; + } + } + + return nb1; + } + + // COMPLIANT + // USE CASE : Compliant use case to check if following is OK : + // - usage of the same variable on different levels of IF statements but with instanceof keys + // - with a variable used 4 times + public int shouldBeCompliantBecauseVariableUsed4TimesWithInstanceOfKeys() + { + int nb1 = 0; + Object obj = new Object(); + + if (obj instanceof String) { + nb1 = 1; + } else { + if (obj instanceof Integer) { + nb1 = 2; + } else { + if (obj instanceof Double) { + nb1 = 3; + } else { + nb1 = 4; + } + } + } + + return nb1; + } + + } diff --git a/java-plugin/src/test/files/AvoidSpringRepositoryCallInLoopCheck.java b/java-plugin/src/test/files/AvoidSpringRepositoryCallInLoopCheck.java index d2ae74e8a..a18b484fd 100644 --- a/java-plugin/src/test/files/AvoidSpringRepositoryCallInLoopCheck.java +++ b/java-plugin/src/test/files/AvoidSpringRepositoryCallInLoopCheck.java @@ -21,16 +21,15 @@ import org.springframework.data.jpa.repository.JpaRepository; import java.util.*; -import java.util.stream.Collectors; -public class AvoidRepositoryCallInLoopCheck { +public class AvoidSpringRepositoryCallInLoopCheck { @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}} + Optional employee = employeeRepository.findById(id); // Noncompliant {{Avoid Spring repository call in loop or stream}} if (employee.isPresent()) { employees.add(employee.get()); } @@ -39,10 +38,20 @@ public List smellGetAllEmployeesByIds(List ids) { } public class Employee { + private Integer id; + private String name; + + public Employee(Integer id, String name) { + this.id = id; + this.name = name; + } + + public Integer getId() { return id; } + public String getName() { return name; } } public interface EmployeeRepository extends JpaRepository { } - + } \ No newline at end of file diff --git a/java-plugin/src/test/files/AvoidSpringRepositoryCallInStreamCheck.java b/java-plugin/src/test/files/AvoidSpringRepositoryCallInStreamCheck.java new file mode 100644 index 000000000..35dc70ce7 --- /dev/null +++ b/java-plugin/src/test/files/AvoidSpringRepositoryCallInStreamCheck.java @@ -0,0 +1,139 @@ +/* + * ecoCode - Java language - Provides rules to reduce the environmental footprint of your Java programs + * Copyright Β© 2023 Green Code Initiative (https://www.ecocode.io) + * + * 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 . + */ +package fr.greencodeinitiative.java.checks; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +public class AvoidSpringRepositoryCallInStreamCheck { + + @Autowired + private EmployeeRepository employeeRepository; + + public void smellGetAllEmployeesByIdsForEach() { + List employees = new ArrayList<>(); + Stream stream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + stream.forEach(id -> { + Optional employee = employeeRepository.findById(id); // Noncompliant {{Avoid Spring repository call in loop or stream}} + if (employee.isPresent()) { + employees.add(employee.get()); + } + }); + } + + public void smellGetAllEmployeesByIdsForEachOrdered() { + List employees = new ArrayList<>(); + Stream stream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + stream.forEachOrdered(id -> { + Optional employee = employeeRepository.findById(id); // Noncompliant {{Avoid Spring repository call in loop or stream}} + if (employee.isPresent()) { + employees.add(employee.get()); + } + }); + } + + public List smellGetAllEmployeesByIdsMap() { + List employees = new ArrayList<>(); + Stream stream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + return stream.map(id -> { + Optional employee = employeeRepository.findById(id); // Noncompliant {{Avoid Spring repository call in loop or stream}} + if (employee.isPresent()) { + employees.add(employee.get()); + } + }) + .collect(Collectors.toList()); + } + + public List smellGetAllEmployeesByIdsPeek() { + List employees = new ArrayList<>(); + Stream stream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + return stream.peek(id -> { + Optional employee = employeeRepository.findById(id); // Noncompliant {{Avoid Spring repository call in loop or stream}} + if (employee.isPresent()) { + employees.add(employee.get()); + } + }) + .collect(Collectors.toList()); + } + + public List smellGetAllEmployeesByIdsWithOptional(List ids) { + List employees = new ArrayList<>(); + return ids + .stream() + .map(element -> { + Employee empl = new Employee(); + employees.add(empl); + return employeeRepository.findById(element).orElse(empl);// Noncompliant {{Avoid Spring repository call in loop or stream}} + }) + .collect(Collectors.toList()); + } + + public List smellGetAllEmployeesByIds(List ids) { + Stream stream = ids.stream(); + return stream.map(element -> { + Employee empl = new Employee(); + employees.add(empl); + return employeeRepository.findById(element);// Noncompliant {{Avoid Spring repository call in loop or stream}} + }) + .collect(Collectors.toList()); + } + + public List smellGetAllEmployeesByIdsWithoutStream(List ids) { + return employeeRepository.findAllById(ids); // Compliant + } + + public List smellDeleteEmployeeById(List ids) { + Stream stream = ids.stream(); + return stream.map(element -> { + Employee empl = new Employee(); + employees.add(empl); + return employeeRepository.deleteById(element);// Noncompliant {{Avoid Spring repository call in loop or stream}} + }) + .collect(Collectors.toList()); + } + + public List smellGetAllEmployeesByIdsWithSeveralMethods(List ids) { + Stream stream = ids.stream(); + return stream.map(element -> { + Employee empl = new Employee(); + return employeeRepository.findById(element).orElse(empl).anotherMethod().anotherOne();// Noncompliant {{Avoid Spring repository call in loop or stream}} + }) + .collect(Collectors.toList()); + } + + public class Employee { + private Integer id; + private String name; + + public Employee(Integer id, String name) { + this.id = id; + this.name = name; + } + + public Integer getId() { return id; } + public String getName() { return name; } + } + + public interface EmployeeRepository extends JpaRepository { + } +} \ No newline at end of file diff --git a/java-plugin/src/test/java/fr/greencodeinitiative/java/JavaCheckRegistrarTest.java b/java-plugin/src/test/java/fr/greencodeinitiative/java/JavaCheckRegistrarTest.java index db1383ae5..c38b4c09b 100644 --- a/java-plugin/src/test/java/fr/greencodeinitiative/java/JavaCheckRegistrarTest.java +++ b/java-plugin/src/test/java/fr/greencodeinitiative/java/JavaCheckRegistrarTest.java @@ -33,6 +33,7 @@ void checkNumberRules() { assertThat(context.checkClasses()).hasSize(19); assertThat(context.testCheckClasses()).isEmpty(); + } } diff --git a/java-plugin/src/test/java/fr/greencodeinitiative/java/checks/AvoidSpringRepositoryCallInLoopCheckTest.java b/java-plugin/src/test/java/fr/greencodeinitiative/java/checks/AvoidSpringRepositoryCallInLoopCheckTest.java index 2ea1887bd..2a855e0c3 100644 --- a/java-plugin/src/test/java/fr/greencodeinitiative/java/checks/AvoidSpringRepositoryCallInLoopCheckTest.java +++ b/java-plugin/src/test/java/fr/greencodeinitiative/java/checks/AvoidSpringRepositoryCallInLoopCheckTest.java @@ -27,7 +27,7 @@ class AvoidSpringRepositoryCallInLoopCheckTest { void test() { CheckVerifier.newVerifier() .onFile("src/test/files/AvoidSpringRepositoryCallInLoopCheck.java") - .withCheck(new AvoidSpringRepositoryCallInLoopCheck()) + .withCheck(new AvoidSpringRepositoryCallInLoopOrStreamCheck()) .withClassPath(FilesUtils.getClassPath("target/test-jars")) .verifyIssues(); } diff --git a/java-plugin/src/test/java/fr/greencodeinitiative/java/checks/AvoidSpringRepositoryCallInStreamCheckTest.java b/java-plugin/src/test/java/fr/greencodeinitiative/java/checks/AvoidSpringRepositoryCallInStreamCheckTest.java new file mode 100644 index 000000000..e9fd4f354 --- /dev/null +++ b/java-plugin/src/test/java/fr/greencodeinitiative/java/checks/AvoidSpringRepositoryCallInStreamCheckTest.java @@ -0,0 +1,35 @@ +/* + * ecoCode - Java language - Provides rules to reduce the environmental footprint of your Java programs + * Copyright Β© 2023 Green Code Initiative (https://www.ecocode.io) + * + * 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 . + */ +package fr.greencodeinitiative.java.checks; + +import fr.greencodeinitiative.java.utils.FilesUtils; +import org.junit.jupiter.api.Test; +import org.sonar.java.checks.verifier.CheckVerifier; + +class AvoidSpringRepositoryCallInStreamCheckTest { + + @Test + void test() { + CheckVerifier.newVerifier() + .onFile("src/test/files/AvoidSpringRepositoryCallInStreamCheck.java") + .withCheck(new AvoidSpringRepositoryCallInLoopOrStreamCheck()) + .withClassPath(FilesUtils.getClassPath("target/test-jars")) + .verifyIssues(); + } + +} diff --git a/java-plugin/src/test/java/fr/greencodeinitiative/java/checks/AvoidUsingGlobalVariablesCheckCheckTest.java b/java-plugin/src/test/java/fr/greencodeinitiative/java/checks/AvoidUsingGlobalVariablesCheckCheckTest.java index f9e270e6c..31e05b156 100644 --- a/java-plugin/src/test/java/fr/greencodeinitiative/java/checks/AvoidUsingGlobalVariablesCheckCheckTest.java +++ b/java-plugin/src/test/java/fr/greencodeinitiative/java/checks/AvoidUsingGlobalVariablesCheckCheckTest.java @@ -20,6 +20,7 @@ import org.junit.jupiter.api.Test; import org.sonar.java.checks.verifier.CheckVerifier; +@Deprecated class AvoidUsingGlobalVariablesCheckCheckTest { @Test @@ -30,4 +31,4 @@ void test() { .verifyIssues(); } -} \ No newline at end of file +} diff --git a/java-plugin/src/test/java/fr/greencodeinitiative/java/checks/UnnecessarilyAssignValuesToVariablesTest.java b/java-plugin/src/test/java/fr/greencodeinitiative/java/checks/UnnecessarilyAssignValuesToVariablesTest.java index 09336e24a..dda74370f 100644 --- a/java-plugin/src/test/java/fr/greencodeinitiative/java/checks/UnnecessarilyAssignValuesToVariablesTest.java +++ b/java-plugin/src/test/java/fr/greencodeinitiative/java/checks/UnnecessarilyAssignValuesToVariablesTest.java @@ -20,6 +20,7 @@ import org.junit.jupiter.api.Test; import org.sonar.java.checks.verifier.CheckVerifier; +@Deprecated class UnnecessarilyAssignValuesToVariablesTest { @Test diff --git a/pom.xml b/pom.xml index 1beefaee1..1c75593ad 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ io.ecocode ecocode-parent - 1.4.1-SNAPSHOT + 1.4.3-SNAPSHOT pom ecoCode Sonar Plugins Project @@ -114,7 +114,7 @@ 2.5.0.1358 - 1.21.0.505 + 1.23.0.740 true 5.9.1