From f8ee1dfe4077948a2551abb1499da211c2413a64 Mon Sep 17 00:00:00 2001 From: benzonico Date: Mon, 21 Oct 2019 08:40:46 +0200 Subject: [PATCH] SONARPY-395 Update documentation for python custom rules (#2172) --- .../src/pages/analysis/languages/python.md | 78 +++++++++++++++++++ .../src/pages/extend/adding-coding-rules.md | 4 +- 2 files changed, 80 insertions(+), 2 deletions(-) diff --git a/server/sonar-docs/src/pages/analysis/languages/python.md b/server/sonar-docs/src/pages/analysis/languages/python.md index e79289a5a83..fe532e8537d 100644 --- a/server/sonar-docs/src/pages/analysis/languages/python.md +++ b/server/sonar-docs/src/pages/analysis/languages/python.md @@ -27,6 +27,84 @@ pylint -r n --msg-template="{path}:{line}: [{msg_id}({symbol ``` Then pass the generated report path to analysis via the `sonar.python.pylint.reportPath` property. + + +## Custom Rules + +### Overview + +The Python analyzer parses the source code, creates an Abstract Syntax Tree (AST) and then walks through the entire tree. A coding rule is a visitor that is able to visit nodes from this AST. + +As soon as the coding rule visits a node, it can navigate its children and log issues if necessary. + +### Writing a Plugin + +Custom rules for Python can be added by writing a SonarQube Plugin and using Python analyzer APIs. +Here are the step to follow: + +#### Create SonarQube Plugin + +* create a standard SonarQube plugin project +* attach this plugin to the SonarQube Python analyzer through the `pom.xml`: + * add the dependency to the Python analyzer. + * add the following line in the sonar-packaging-maven-plugin configuration. + ``` + python:2.0-SNAPSHOT + ``` +* implement the following extension points: + * [Plugin](http://javadocs.sonarsource.org/latest/apidocs/org/sonar/api/Plugin.html) + * [RulesDefinition](http://javadocs.sonarsource.org/latest/apidocs/org/sonar/api/server/rule/RulesDefinition.html) and [PythonCustomRuleRepository](https://github.com/SonarSource/sonar-python/blob/master/python-frontend/src/main/java/org/sonar/plugins/python/api/PythonCustomRuleRepository.java), which can be implemented by a single class, to declare your custom rules +* declare the RulesDefinition as an extension in the Plugin extension point. + +#### Implement a Rule + +* create a class that will hold the implementation of the rule, it should: + * extend `PythonCheckTree` or `PythonSubscriptionCheck` + * define the rule name, key, tags, etc. with Java annotations. +* declare this class in the `RulesDefinition`. + +### Example Plugin + +To get started a sample plugin can be found here: [python-custom-rules](https://github.com/SonarSource/sonar-custom-rules-examples/tree/master/python-custom-rules). + +#### Implementation Details + +**Using `PythonCheckTree`** + +To explore a part of the AST, override a method from the PythonCheckTree. For example, if you want to explore "if statement" nodes, override [PythonCheckTree#visitIfStatement](https://github.com/SonarSource/sonar-python/blob/39b6126e9fdef42b93004cf6cc5818e861051334/python-frontend/src/main/java/org/sonar/plugins/python/api/tree/BaseTreeVisitor.java#L56) method that will be called each time an [ifStatement](https://github.com/SonarSource/sonar-python/blob/master/python-frontend/src/main/java/org/sonar/plugins/python/api/tree/IfStatement.java) node is encountered in the AST. + +![](/images/exclamation.svg) When overriding a visit method, you must call the super method in order to allow the visitor to visit the children the node. + +**Using `PythonSubscriptionCheck`** + +To explore a part of the AST, override [`PythonSubscriptionCheck#initialize`](https://github.com/SonarSource/sonar-python/blob/master/python-frontend/src/main/java/org/sonar/plugins/python/api/SubscriptionCheck.java#L26) and call the [`SubscriptionCheck.Context#registerSyntaxNodeConsumer`](https://github.com/SonarSource/sonar-python/blob/master/python-frontend/src/main/java/org/sonar/plugins/python/api/SubscriptionCheck.java) with the [`Tree#Kind`](https://github.com/SonarSource/sonar-python/blob/master/python-frontend/src/main/java/org/sonar/plugins/python/api/tree/Tree.java#L42) of node you want to visit. For example, if you want to explore "if statement" you should register to the kind [`Tree#Kind#IF_STATEMENT`](https://github.com/SonarSource/sonar-python/blob/master/python-frontend/src/main/java/org/sonar/plugins/python/api/tree/Tree.java#L97) and then provide a lambda that will consume a [`SubscriptionContext`](https://github.com/SonarSource/sonar-python/blob/master/python-frontend/src/main/java/org/sonar/plugins/python/api/SubscriptionContext.java#L27) to act on such ndoes. + +**Create Issues** + +From the check, issue can be created by calling [`SubscriptionContext#addIssue`](https://github.com/SonarSource/sonar-python/blob/master/python-frontend/src/main/java/org/sonar/plugins/python/api/SubscriptionContext.java#L30) method or [`PythonCheckTree#addIssue`](https://github.com/SonarSource/sonar-python/blob/master/python-frontend/src/main/java/org/sonar/plugins/python/api/PythonCheckTree.java#L36) method. + +**Testing Checks** + +To test custom checks you can use method [`PythonCheckVerifier#verify`](https://github.com/SonarSource/sonar-python/blob/master/python-checks-testkit/src/main/java/org/sonar/python/checks/utils/PythonCheckVerifier.java). Don't forget to add the testkit dependency to access this class from your project : + ``` + + org.sonarsource.python + python-checks-testkit + ${project.version} + test + + ``` + +You should end each line with an issue with a comment in the following form: + +``` +# Noncompliant {{Message}} +``` + +Comment syntax is described [here](https://github.com/SonarSource/sonar-analyzer-commons/blob/master/test-commons/README.md). + + + ## Related Pages * [Importing External Issues](/analysis/external-issues/) ([Pylint](http://www.pylint.org/), [Bandit](https://github.com/PyCQA/bandit/blob/master/README.rst)) * [Test Coverage & Execution](/analysis/coverage/) (the [Coverage Tool](http://nedbatchelder.com/code/coverage/) provided by [Ned Batchelder](http://nedbatchelder.com/), [Nose](https://nose.readthedocs.org/en/latest/), [pytest](https://docs.pytest.org/en/latest/)) diff --git a/server/sonar-docs/src/pages/extend/adding-coding-rules.md b/server/sonar-docs/src/pages/extend/adding-coding-rules.md index 041267a67f0..d2aeaee5a16 100644 --- a/server/sonar-docs/src/pages/extend/adding-coding-rules.md +++ b/server/sonar-docs/src/pages/extend/adding-coding-rules.md @@ -26,7 +26,7 @@ JavaScript | - | ![](/images/check.svg) | - PHP | - | ![](/images/check.svg)| - PL/SQL | ![](/images/check.svg) | - | - PL/I | ![](/images/check.svg) | - | - -Python | Deprecated | - | - +Python | - | ![](/images/check.svg) | - RPG | - | ![](/images/check.svg)| - VB.NET| - | - | ![](/images/check.svg)[Importing Issues from Third-Party Roslyn Analyzers (C#, VB.NET)](/analysis/external-issues/) XML | ![](/images/check.svg) | - | - @@ -48,6 +48,7 @@ See the following pages to see samples and details about how to create coding ru * [for Java](/analysis/languages/java/) * [for JavaScript](/analysis/languages/javascript/) * [for PHP](/analysis/languages/php/) +* [for Python](/analysis/languages/python/) * [for RPG](/analysis/languages/rpg/) @@ -67,7 +68,6 @@ The latest version of SSLR Toolkit can be downloaded from following locations: * [Flex](https://binaries.sonarsource.com/Distribution/sonar-flex-plugin/) * [PL/SQL](https://binaries.sonarsource.com/CommercialDistribution/sslr-plsql-toolkit/) * [PL/I](https://binaries.sonarsource.com/CommercialDistribution/sslr-pli-toolkit/) -* [Python](https://binaries.sonarsource.com/Distribution/sslr-python-toolkit/) (Deprecated) For an SSLR preview, consider the following source code sample: ``` -- 2.39.5