From 16cb529545b47ea5cdc321ddd7c143212a383e98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Kaszab?= <27868208+PeterKaszab@users.noreply.github.com> Date: Mon, 10 Oct 2022 16:56:28 +0200 Subject: [PATCH 01/12] [feat] Add roslynator support to report-converter --- .../analyzers/roslynator/__init__.py | 7 ++ .../analyzers/roslynator/analyzer_result.py | 103 ++++++++++++++++++ .../roslynator_output_test_files/Makefile | 2 + .../Sample.cs.expected.plist | 69 ++++++++++++ .../files/.gitignore | 2 + .../files/Sample.cs | 10 ++ .../files/files.csproj | 9 ++ .../roslynator_output_test_files/out.xml | 21 ++++ .../unit/analyzers/test_roslynator_parser.py | 81 ++++++++++++++ 9 files changed, 304 insertions(+) create mode 100644 tools/report-converter/codechecker_report_converter/analyzers/roslynator/__init__.py create mode 100644 tools/report-converter/codechecker_report_converter/analyzers/roslynator/analyzer_result.py create mode 100644 tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/Makefile create mode 100644 tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/Sample.cs.expected.plist create mode 100644 tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/files/.gitignore create mode 100644 tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/files/Sample.cs create mode 100644 tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/files/files.csproj create mode 100644 tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/out.xml create mode 100644 tools/report-converter/tests/unit/analyzers/test_roslynator_parser.py diff --git a/tools/report-converter/codechecker_report_converter/analyzers/roslynator/__init__.py b/tools/report-converter/codechecker_report_converter/analyzers/roslynator/__init__.py new file mode 100644 index 0000000000..4259749345 --- /dev/null +++ b/tools/report-converter/codechecker_report_converter/analyzers/roslynator/__init__.py @@ -0,0 +1,7 @@ +# ------------------------------------------------------------------------- +# +# Part of the CodeChecker project, under the Apache License v2.0 with +# LLVM Exceptions. See LICENSE for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +# ------------------------------------------------------------------------- diff --git a/tools/report-converter/codechecker_report_converter/analyzers/roslynator/analyzer_result.py b/tools/report-converter/codechecker_report_converter/analyzers/roslynator/analyzer_result.py new file mode 100644 index 0000000000..32f8984ad6 --- /dev/null +++ b/tools/report-converter/codechecker_report_converter/analyzers/roslynator/analyzer_result.py @@ -0,0 +1,103 @@ +# ------------------------------------------------------------------------- +# +# Part of the CodeChecker project, under the Apache License v2.0 with +# LLVM Exceptions. See LICENSE for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +# ------------------------------------------------------------------------- + +import logging +import os +import xml.etree.ElementTree as ET + +from typing import Dict, List, Optional + +from codechecker_report_converter.report import File, get_or_create_file, \ + Report + +from ..analyzer_result import AnalyzerResultBase + + +LOG = logging.getLogger('report-converter') + + +class AnalyzerResult(AnalyzerResultBase): + """ Transform analyzer result of Roslynator. """ + + TOOL_NAME = 'roslynator' + NAME = 'Roslynator' + URL = 'https://github.com/JosefPihrt/Roslynator' + + def __init__(self): + super(AnalyzerResult, self).__init__() + self.__file_cache: Dict[str, File] = {} + + def get_reports( + self, + file_path: str + ) -> List[Report]: + """ Get reports from the given analyzer result. """ + reports: List[Report] = [] + + root = self.__parse_analyzer_result(file_path) + if root is None: + return reports + + for diag in root.findall('./CodeAnalysis/Projects/*/Diagnostics/*'): + report = self.__parse_diag(diag, file_path) + if report is not None: + reports.append(report) + + return reports + + + def __parse_analyzer_result( + self, + analyzer_result: str + ) -> Optional[ET.Element]: + """ Parse the given analyzer result xml file. + + Returns the root element of the parsed tree or None if something goes + wrong. + """ + try: + tree = ET.parse(analyzer_result) + return tree.getroot() + except OSError: + LOG.error("Analyzer result does not exist: %s", analyzer_result) + except ET.ParseError: + LOG.error("Failed to parse the given analyzer result '%s'. Please " + "give a valid xml file with messages generated by " + "Roslynator.", analyzer_result) + + + def __parse_diag( + self, + diag: ET.Element, + input_file_path: str + ) -> Optional[Report]: + """ Parse the given Roslynator diagnostic + + Returns the Report from the parsed diagnostic or None if something goes + wrong. + """ + analyzer_id = diag.get('Id') + message = diag.find('Message').text + source_file_path = os.path.join(os.path.dirname(input_file_path), + diag.find('FilePath').text) + + location = diag.find('Location') + line = location.get('Line') + column = location.get('Character') + + if os.path.exists(source_file_path): + return Report( + get_or_create_file(source_file_path, self.__file_cache), + int(line), + int(column), + message, + analyzer_id + ) + else: + LOG.warning("Source file does not exists: %s", source_file_path) + diff --git a/tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/Makefile b/tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/Makefile new file mode 100644 index 0000000000..eeebc03994 --- /dev/null +++ b/tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/Makefile @@ -0,0 +1,2 @@ +all: + roslynator analyze files/files.csproj -o out.xml diff --git a/tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/Sample.cs.expected.plist b/tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/Sample.cs.expected.plist new file mode 100644 index 0000000000..d6eff555df --- /dev/null +++ b/tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/Sample.cs.expected.plist @@ -0,0 +1,69 @@ + + + + + diagnostics + + + category + unknown + check_name + CA1822 + description + Mark members as static + issue_hash_content_of_line_in_context + 057dcbd39881ede94293d9a9048304ac + location + + col + 16 + file + 0 + line + 5 + + path + + + depth + 0 + kind + event + location + + col + 16 + file + 0 + line + 5 + + message + Mark members as static + + + type + roslynator + + + files + + files/Sample.cs + + metadata + + analyzer + + name + roslynator + + generated_by + + name + report-converter + version + x.y.z + + + + diff --git a/tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/files/.gitignore b/tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/files/.gitignore new file mode 100644 index 0000000000..cbbd0b5c02 --- /dev/null +++ b/tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/files/.gitignore @@ -0,0 +1,2 @@ +bin/ +obj/ \ No newline at end of file diff --git a/tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/files/Sample.cs b/tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/files/Sample.cs new file mode 100644 index 0000000000..36d10e644c --- /dev/null +++ b/tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/files/Sample.cs @@ -0,0 +1,10 @@ +namespace files; + +public class Sample +{ + public int Add(int a, int b) + { + int x; + return a + b; + } +} diff --git a/tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/files/files.csproj b/tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/files/files.csproj new file mode 100644 index 0000000000..0b86e395c9 --- /dev/null +++ b/tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/files/files.csproj @@ -0,0 +1,9 @@ + + + + net6.0 + disable + enable + + + diff --git a/tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/out.xml b/tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/out.xml new file mode 100644 index 0000000000..7d9ed2a502 --- /dev/null +++ b/tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/out.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + Info + Mark members as static + files/Sample.cs + + + + + + + \ No newline at end of file diff --git a/tools/report-converter/tests/unit/analyzers/test_roslynator_parser.py b/tools/report-converter/tests/unit/analyzers/test_roslynator_parser.py new file mode 100644 index 0000000000..c122ed43b4 --- /dev/null +++ b/tools/report-converter/tests/unit/analyzers/test_roslynator_parser.py @@ -0,0 +1,81 @@ +# ------------------------------------------------------------------------- +# +# Part of the CodeChecker project, under the Apache License v2.0 with +# LLVM Exceptions. See LICENSE for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +# ------------------------------------------------------------------------- + +""" +This module tests the correctness of the RoslynatorAnalyzerResult, which +used in sequence transform Roslynator output to a plist file. +""" + +import os +import plistlib +import shutil +import tempfile +import unittest + +from codechecker_report_converter.analyzers.roslynator import analyzer_result +from codechecker_report_converter.report.parser import plist + + +class RoslynatorAnalyzerResultTestCase(unittest.TestCase): + """ Test the output of the RoslynatorAnalyzerResult. """ + + def setUp(self): + """ Setup the test. """ + self.analyzer_result = analyzer_result.AnalyzerResult() + self.cc_result_dir = tempfile.mkdtemp() + self.test_files = os.path.join(os.path.dirname(__file__), + 'roslynator_output_test_files') + + def tearDown(self): + """ Clean temporary directory. """ + shutil.rmtree(self.cc_result_dir) + + def test_no_roslynator_output_file(self): + """ Test transforming single C# file. """ + analyzer_result = os.path.join(self.test_files, 'files', + 'Sample.cs') + + ret = self.analyzer_result.transform( + analyzer_result, self.cc_result_dir, plist.EXTENSION, + file_name="{source_file}_{analyzer}") + self.assertFalse(ret) + + def test_transform_dir(self): + """ Test transforming a directory. """ + analyzer_result = os.path.join(self.test_files) + + ret = self.analyzer_result.transform( + analyzer_result, self.cc_result_dir, plist.EXTENSION, + file_name="{source_file}_{analyzer}") + self.assertFalse(ret) + + def test_transform_single_file(self): + """ Test transforming single output file. """ + analyzer_result = os.path.join(self.test_files, 'out.xml') + self.analyzer_result.transform( + analyzer_result, self.cc_result_dir, plist.EXTENSION, + file_name="{source_file}_{analyzer}") + + plist_file = os.path.join(self.cc_result_dir, + 'Sample.cs_roslynator.plist') + + with open(plist_file, mode='rb') as pfile: + res = plistlib.load(pfile) + + # Use relative path for this test. + res['files'][0] = os.path.join('files', 'Sample.cs') + + self.assertTrue(res['metadata']['generated_by']['version']) + res['metadata']['generated_by']['version'] = "x.y.z" + + plist_file = os.path.join(self.test_files, + 'Sample.cs.expected.plist') + with open(plist_file, mode='rb') as pfile: + exp = plistlib.load(pfile) + + self.assertEqual(res, exp) \ No newline at end of file From 4e24f23f4ad75a13c9b4177bc2eb0c741d1f7a25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Kaszab?= <27868208+PeterKaszab@users.noreply.github.com> Date: Fri, 14 Oct 2022 11:59:25 +0200 Subject: [PATCH 02/12] Add documentation for Roslynator --- docs/tools/report-converter.md | 32 +++++++++++++++++++ .../analyzers/roslynator/analyzer_result.py | 4 +-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/docs/tools/report-converter.md b/docs/tools/report-converter.md index b1aa9f2d26..c3f9472e98 100644 --- a/docs/tools/report-converter.md +++ b/docs/tools/report-converter.md @@ -28,6 +28,7 @@ a CodeChecker server. * [Sphinx](#sphinx) * [Sparse](#sparse) * [cpplint](#cpplint) + * [Roslynator.DotNet.Cli](#roslynator-dotnet-cli) * [Plist to html tool](#plist-to-html-tool) * [Usage](#usage-1) * [Report hash generation module](#report-hash-generation-module) @@ -585,6 +586,37 @@ report-converter -t cpplint -o ./codechecker_cpplint_reports ./sample.out CodeChecker store ./codechecker_cpplint_reports -n cpplint ``` +### [Roslynator.DotNet.Cli](https://github.com/JosefPihrt/Roslynator#roslynator-command-line-tool-) +The [Roslynator](https://github.com/JosefPihrt/Roslynator) project contains +several analyzers built on top of Microsoft Roslyn. + +It also provides a [command-line tool](https://github.com/JosefPihrt/Roslynator#roslynator-command-line-tool-) which is able to run Roslyn +code-analysis from the command line line. +It is not limited to Microsoft and Roslynator analyzers, it supports any +Roslyn anaylzer. It can also report MSBuild compiler diagnostics. + +The recommended way of running the roslynator cli tool is to save the +output to a xml file and give this file to the report converter tool. + +The following example shows you how to run roslynator cli and store the results +found by roslynator to the CodeChecker database. + +```sh +# Change Directory to your project +cd path/to/your/ProjectOrSolution + +# Run roslynator +# Provide a sln file if you want to analyze a solution +roslynator analyze Sample.csproj --output sample.xml + +# Use 'report-converter' to create a CodeChecker report directory from the +# analyzer result of roslynator +report-converter -t roslynator -o ./codechecker_roslynator_reports ./sample.xml + +# Store the roslynator with CodeChecker. +CodeChecker store ./codechecker_roslynator_reports -n roslynator +``` + ## Plist to html tool `plist-to-html` is a python tool which parses and creates HTML files from one or more `.plist` result files. diff --git a/tools/report-converter/codechecker_report_converter/analyzers/roslynator/analyzer_result.py b/tools/report-converter/codechecker_report_converter/analyzers/roslynator/analyzer_result.py index 32f8984ad6..43ec304f21 100644 --- a/tools/report-converter/codechecker_report_converter/analyzers/roslynator/analyzer_result.py +++ b/tools/report-converter/codechecker_report_converter/analyzers/roslynator/analyzer_result.py @@ -25,8 +25,8 @@ class AnalyzerResult(AnalyzerResultBase): """ Transform analyzer result of Roslynator. """ TOOL_NAME = 'roslynator' - NAME = 'Roslynator' - URL = 'https://github.com/JosefPihrt/Roslynator' + NAME = 'Roslynator.DotNet.Cli' + URL = 'https://github.com/JosefPihrt/Roslynator#roslynator-command-line-tool-' def __init__(self): super(AnalyzerResult, self).__init__() From 69f7ddeaf83bb8bff60269233768a7f5d5b0a36b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Kaszab?= <27868208+PeterKaszab@users.noreply.github.com> Date: Fri, 14 Oct 2022 12:05:10 +0200 Subject: [PATCH 03/12] Update docs: add links to roslynator --- docs/README.md | 1 + docs/tools/report-converter.md | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/README.md b/docs/README.md index 839a3e8f9c..7bbcae7588 100644 --- a/docs/README.md +++ b/docs/README.md @@ -176,6 +176,7 @@ The following tools are supported: | | [Kernel-Doc](/docs/tools/report-converter.md#kernel-doc) | | | [Sparse](/docs/tools/report-converter.md#sparse) | | | [cpplint](/docs/tools/report-converter.md#cpplint) | +| **C#** | [Roslynator.DotNet.Cli](/docs/tools/report-converter.md#roslynatordotnetcli) | | **Java** | [SpotBugs](/docs/tools/report-converter.md#spotbugs) | | | [Facebook Infer](/docs/tools/report-converter.md#fbinfer) | | **Python** | [Pylint](/docs/tools/report-converter.md#pylint) | diff --git a/docs/tools/report-converter.md b/docs/tools/report-converter.md index c3f9472e98..df7f3d3225 100644 --- a/docs/tools/report-converter.md +++ b/docs/tools/report-converter.md @@ -28,7 +28,7 @@ a CodeChecker server. * [Sphinx](#sphinx) * [Sparse](#sparse) * [cpplint](#cpplint) - * [Roslynator.DotNet.Cli](#roslynator-dotnet-cli) + * [Roslynator.DotNet.Cli](#roslynatordotnetcli) * [Plist to html tool](#plist-to-html-tool) * [Usage](#usage-1) * [Report hash generation module](#report-hash-generation-module) @@ -73,7 +73,7 @@ optional arguments: Currently supported output types are: asan, clang- tidy, coccinelle, cppcheck, cpplint, eslint, fbinfer, golint, kernel-doc, lsan, mdl, msan, - pyflakes, pylint, smatch, sparse, sphinx, spotbugs, + pyflakes, pylint, roslynator, smatch, sparse, sphinx, spotbugs, tsan, tslint, ubsan. --meta [META [META ...]] Metadata information which will be stored alongside From 2d3c0672f8b45769f83d194c1e0040cc743fc28d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Kaszab?= <27868208+PeterKaszab@users.noreply.github.com> Date: Fri, 14 Oct 2022 12:07:46 +0200 Subject: [PATCH 04/12] Spelling --- docs/tools/report-converter.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/tools/report-converter.md b/docs/tools/report-converter.md index df7f3d3225..06aa82c6a2 100644 --- a/docs/tools/report-converter.md +++ b/docs/tools/report-converter.md @@ -596,7 +596,7 @@ It is not limited to Microsoft and Roslynator analyzers, it supports any Roslyn anaylzer. It can also report MSBuild compiler diagnostics. The recommended way of running the roslynator cli tool is to save the -output to a xml file and give this file to the report converter tool. +output to an XML file and give this file to the report converter tool. The following example shows you how to run roslynator cli and store the results found by roslynator to the CodeChecker database. @@ -606,7 +606,7 @@ found by roslynator to the CodeChecker database. cd path/to/your/ProjectOrSolution # Run roslynator -# Provide a sln file if you want to analyze a solution +# Provide an SLN file if you want to analyze a solution roslynator analyze Sample.csproj --output sample.xml # Use 'report-converter' to create a CodeChecker report directory from the From 49763bfb119adc271a0bb61b6fa9098e54913aee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Kaszab?= <27868208+PeterKaszab@users.noreply.github.com> Date: Fri, 14 Oct 2022 12:10:00 +0200 Subject: [PATCH 05/12] Update roslynator commands in report-converter.md --- docs/tools/report-converter.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/tools/report-converter.md b/docs/tools/report-converter.md index 06aa82c6a2..7ddf598f20 100644 --- a/docs/tools/report-converter.md +++ b/docs/tools/report-converter.md @@ -603,11 +603,11 @@ found by roslynator to the CodeChecker database. ```sh # Change Directory to your project -cd path/to/your/ProjectOrSolution +cd path/to/your/project_or_solution # Run roslynator # Provide an SLN file if you want to analyze a solution -roslynator analyze Sample.csproj --output sample.xml +roslynator analyze sample.csproj --output sample.xml # Use 'report-converter' to create a CodeChecker report directory from the # analyzer result of roslynator From 09325bfd749313021cbf0898b6d39486e6a83978 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Kaszab?= <27868208+PeterKaszab@users.noreply.github.com> Date: Sun, 16 Oct 2022 15:25:53 +0200 Subject: [PATCH 06/12] Handle if a diagnostic does not belong to a file --- .../analyzers/roslynator/analyzer_result.py | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/tools/report-converter/codechecker_report_converter/analyzers/roslynator/analyzer_result.py b/tools/report-converter/codechecker_report_converter/analyzers/roslynator/analyzer_result.py index 43ec304f21..472c3e68ee 100644 --- a/tools/report-converter/codechecker_report_converter/analyzers/roslynator/analyzer_result.py +++ b/tools/report-converter/codechecker_report_converter/analyzers/roslynator/analyzer_result.py @@ -81,23 +81,29 @@ def __parse_diag( Returns the Report from the parsed diagnostic or None if something goes wrong. """ - analyzer_id = diag.get('Id') - message = diag.find('Message').text + id = diag.get('Id') + + filePathElement = diag.find('FilePath') + if filePathElement is None: + LOG.warning("Diagnostic does not belong to a file: %s", id) + return None + source_file_path = os.path.join(os.path.dirname(input_file_path), - diag.find('FilePath').text) + filePathElement.text) + if not os.path.exists(source_file_path): + LOG.warning("Source file does not exist: %s", source_file_path) + return None + message = diag.find('Message').text location = diag.find('Location') line = location.get('Line') column = location.get('Character') - if os.path.exists(source_file_path): - return Report( - get_or_create_file(source_file_path, self.__file_cache), - int(line), - int(column), - message, - analyzer_id - ) - else: - LOG.warning("Source file does not exists: %s", source_file_path) + return Report( + get_or_create_file(source_file_path, self.__file_cache), + int(line), + int(column), + message, + id + ) From fb851b7a619b0b62bfc0edb8db1bd09f6075694f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Kaszab?= <27868208+PeterKaszab@users.noreply.github.com> Date: Sun, 16 Oct 2022 15:31:55 +0200 Subject: [PATCH 07/12] Improve unit tests --- .../roslynator_output_test_files/Makefile | 2 +- .../Sample.cs.expected.plist | 45 ++++++++++++++++++- .../files/Sample.cs | 13 +++++- .../files/files.csproj | 1 + .../roslynator_output_test_files/out.xml | 17 +++++-- 5 files changed, 70 insertions(+), 8 deletions(-) diff --git a/tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/Makefile b/tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/Makefile index eeebc03994..305b828420 100644 --- a/tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/Makefile +++ b/tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/Makefile @@ -1,2 +1,2 @@ all: - roslynator analyze files/files.csproj -o out.xml + roslynator analyze files/files.csproj --output out.xml diff --git a/tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/Sample.cs.expected.plist b/tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/Sample.cs.expected.plist index d6eff555df..934d310796 100644 --- a/tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/Sample.cs.expected.plist +++ b/tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/Sample.cs.expected.plist @@ -4,6 +4,47 @@ diagnostics + + category + unknown + check_name + CA1806 + description + Do not ignore method results + issue_hash_content_of_line_in_context + 70e00602407f8f0820dad202635fd677 + location + + col + 9 + file + 0 + line + 17 + + path + + + depth + 0 + kind + event + location + + col + 9 + file + 0 + line + 17 + + message + Do not ignore method results + + + type + roslynator + category unknown @@ -20,7 +61,7 @@ file 0 line - 5 + 9 path @@ -36,7 +77,7 @@ file 0 line - 5 + 9 message Mark members as static diff --git a/tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/files/Sample.cs b/tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/files/Sample.cs index 36d10e644c..f04d58b51e 100644 --- a/tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/files/Sample.cs +++ b/tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/files/Sample.cs @@ -1,10 +1,19 @@ -namespace files; +using System.Collections.Generic; +using System.Linq; + +namespace files; public class Sample { + // Triggers CA1822 public int Add(int a, int b) { - int x; return a + b; } + + // Triggers CA1806 + public void AddOne(IEnumerable enumerable) + { + enumerable.Select(n => Add(1, n)); + } } diff --git a/tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/files/files.csproj b/tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/files/files.csproj index 0b86e395c9..cb77f8c289 100644 --- a/tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/files/files.csproj +++ b/tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/files/files.csproj @@ -4,6 +4,7 @@ net6.0 disable enable + AllEnabledByDefault diff --git a/tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/out.xml b/tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/out.xml index 7d9ed2a502..c685bdcade 100644 --- a/tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/out.xml +++ b/tools/report-converter/tests/unit/analyzers/roslynator_output_test_files/out.xml @@ -2,17 +2,28 @@ + + - + + Warning + Mark assemblies with CLSCompliant + + + Warning + Do not ignore method results + files/Sample.cs + + - Info + Warning Mark members as static files/Sample.cs - + From b72fc2c132f2760a93437d62a74108d3775f5660 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Kaszab?= <27868208+PeterKaszab@users.noreply.github.com> Date: Sun, 16 Oct 2022 15:43:25 +0200 Subject: [PATCH 08/12] Imporve report-convert.md --- docs/tools/report-converter.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/tools/report-converter.md b/docs/tools/report-converter.md index 7ddf598f20..bb302d8e37 100644 --- a/docs/tools/report-converter.md +++ b/docs/tools/report-converter.md @@ -590,30 +590,30 @@ CodeChecker store ./codechecker_cpplint_reports -n cpplint The [Roslynator](https://github.com/JosefPihrt/Roslynator) project contains several analyzers built on top of Microsoft Roslyn. -It also provides a [command-line tool](https://github.com/JosefPihrt/Roslynator#roslynator-command-line-tool-) which is able to run Roslyn -code-analysis from the command line line. +It also provides a [.NET tool](https://github.com/JosefPihrt/Roslynator#roslynator-command-line-tool-) +for running Roslyn code analysis from the command line. It is not limited to Microsoft and Roslynator analyzers, it supports any Roslyn anaylzer. It can also report MSBuild compiler diagnostics. -The recommended way of running the roslynator cli tool is to save the +The recommended way of running the Roslynator CLI tool is to save the output to an XML file and give this file to the report converter tool. -The following example shows you how to run roslynator cli and store the results -found by roslynator to the CodeChecker database. +The following example shows you how to run Roslynator CLI and store the results +found by Roslynator to the CodeChecker database. ```sh -# Change Directory to your project +# Change directory to your project cd path/to/your/project_or_solution -# Run roslynator -# Provide an SLN file if you want to analyze a solution +# Run Roslynator +# Provide an .sln file instead of .csproj if you want to analyze a solution roslynator analyze sample.csproj --output sample.xml # Use 'report-converter' to create a CodeChecker report directory from the -# analyzer result of roslynator +# analyzer result of Roslynator report-converter -t roslynator -o ./codechecker_roslynator_reports ./sample.xml -# Store the roslynator with CodeChecker. +# Store the Roslynator report with CodeChecker CodeChecker store ./codechecker_roslynator_reports -n roslynator ``` From 2c025e526c4e11ad81347a833f7fdb5974a6d9db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Kaszab?= <27868208+PeterKaszab@users.noreply.github.com> Date: Sun, 16 Oct 2022 15:45:29 +0200 Subject: [PATCH 09/12] Add Roslynator to supported_code_analyzers --- docs/supported_code_analyzers.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/supported_code_analyzers.md b/docs/supported_code_analyzers.md index 7cc03d298a..c4803c3700 100644 --- a/docs/supported_code_analyzers.md +++ b/docs/supported_code_analyzers.md @@ -21,6 +21,7 @@ CodeChecker result directory which can be stored to a CodeChecker server. | | [Kernel-Doc](/docs/tools/report-converter.md#kernel-doc) | ✓ | | | [Sparse](/docs/tools/report-converter.md#sparse) | ✓ | | | [cpplint](/docs/tools/report-converter.md#cpplint) | ✓ | +| **C#** | [Roslynator.DotNet.Cli](/docs/tools/report-converter.md#roslynatordotnetcli) | ✓ | | **Java** | [FindBugs](http://findbugs.sourceforge.net/) | ✗ | | | [SpotBugs](/docs/tools/report-converter.md#spotbugs) | ✓ | | | [Facebook Infer](/docs/tools/report-converter.md#fbinfer) | ✓ | From b7344507394b04ebea7d2634ece85817d10533bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Kaszab?= <27868208+PeterKaszab@users.noreply.github.com> Date: Sun, 16 Oct 2022 15:53:54 +0200 Subject: [PATCH 10/12] Add missing references to Roslynator --- docs/tools/report-converter.md | 1 + snap/snapcraft.yaml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/tools/report-converter.md b/docs/tools/report-converter.md index bb302d8e37..69c71b681a 100644 --- a/docs/tools/report-converter.md +++ b/docs/tools/report-converter.md @@ -113,6 +113,7 @@ Supported analyzers: msan - MemorySanitizer, https://clang.llvm.org/docs/MemorySanitizer.html pyflakes - Pyflakes, https://github.com/PyCQA/pyflakes pylint - Pylint, https://www.pylint.org + roslynator - Roslynator.DotNet.Cli, https://github.com/JosefPihrt/Roslynator#roslynator-command-line-tool- smatch - Smatch, https://repo.or.cz/w/smatch.git sparse - Sparse, https://git.kernel.org/pub/scm/devel/sparse/sparse.git sphinx - Sphinx, https://github.com/sphinx-doc/sphinx diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 4a8de44e9d..936a58d4c6 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -7,7 +7,7 @@ description: | You can store and visualize thousands of analysis reports of many analyzers like Clang Static Analyzer (C/C++), Clang Tidy (C/C++), Facebook Infer (C/C++, Java), Clang Sanitizers (C/C++), Spotbugs (Java), Pylint (Python), - Eslint (Javascript). + Roslynator.DotNet.Cli (C#), Eslint (Javascript). grade: stable confinement: classic From 830a32224a404218811a93dd01d72f0a82396339 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Kaszab?= <27868208+PeterKaszab@users.noreply.github.com> Date: Sun, 16 Oct 2022 16:52:05 +0200 Subject: [PATCH 11/12] Revert snapscraft.yaml --- snap/snapcraft.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 936a58d4c6..4a8de44e9d 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -7,7 +7,7 @@ description: | You can store and visualize thousands of analysis reports of many analyzers like Clang Static Analyzer (C/C++), Clang Tidy (C/C++), Facebook Infer (C/C++, Java), Clang Sanitizers (C/C++), Spotbugs (Java), Pylint (Python), - Roslynator.DotNet.Cli (C#), Eslint (Javascript). + Eslint (Javascript). grade: stable confinement: classic From b4754da728e44efd95cc95d90aa2556186ef7cf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Kaszab?= <27868208+PeterKaszab@users.noreply.github.com> Date: Sat, 22 Oct 2022 13:39:44 +0200 Subject: [PATCH 12/12] Fix tests --- .../analyzers/roslynator/analyzer_result.py | 20 +++++++++---------- .../unit/analyzers/test_roslynator_parser.py | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/tools/report-converter/codechecker_report_converter/analyzers/roslynator/analyzer_result.py b/tools/report-converter/codechecker_report_converter/analyzers/roslynator/analyzer_result.py index 472c3e68ee..31becc1c7d 100644 --- a/tools/report-converter/codechecker_report_converter/analyzers/roslynator/analyzer_result.py +++ b/tools/report-converter/codechecker_report_converter/analyzers/roslynator/analyzer_result.py @@ -26,7 +26,8 @@ class AnalyzerResult(AnalyzerResultBase): TOOL_NAME = 'roslynator' NAME = 'Roslynator.DotNet.Cli' - URL = 'https://github.com/JosefPihrt/Roslynator#roslynator-command-line-tool-' + URL = 'https://github.com/JosefPihrt/Roslynator' \ + + '#roslynator-command-line-tool-' def __init__(self): super(AnalyzerResult, self).__init__() @@ -50,7 +51,6 @@ def get_reports( return reports - def __parse_analyzer_result( self, analyzer_result: str @@ -65,23 +65,24 @@ def __parse_analyzer_result( return tree.getroot() except OSError: LOG.error("Analyzer result does not exist: %s", analyzer_result) + return None except ET.ParseError: LOG.error("Failed to parse the given analyzer result '%s'. Please " "give a valid xml file with messages generated by " "Roslynator.", analyzer_result) - + return None def __parse_diag( self, - diag: ET.Element, + diag, input_file_path: str ) -> Optional[Report]: """ Parse the given Roslynator diagnostic - + Returns the Report from the parsed diagnostic or None if something goes wrong. """ - id = diag.get('Id') + id = diag.attrib.get('Id') filePathElement = diag.find('FilePath') if filePathElement is None: @@ -89,15 +90,15 @@ def __parse_diag( return None source_file_path = os.path.join(os.path.dirname(input_file_path), - filePathElement.text) + filePathElement.text) if not os.path.exists(source_file_path): LOG.warning("Source file does not exist: %s", source_file_path) return None message = diag.find('Message').text location = diag.find('Location') - line = location.get('Line') - column = location.get('Character') + line = location.attrib.get('Line') + column = location.attrib.get('Character') return Report( get_or_create_file(source_file_path, self.__file_cache), @@ -106,4 +107,3 @@ def __parse_diag( message, id ) - diff --git a/tools/report-converter/tests/unit/analyzers/test_roslynator_parser.py b/tools/report-converter/tests/unit/analyzers/test_roslynator_parser.py index c122ed43b4..15137ddfdc 100644 --- a/tools/report-converter/tests/unit/analyzers/test_roslynator_parser.py +++ b/tools/report-converter/tests/unit/analyzers/test_roslynator_parser.py @@ -78,4 +78,4 @@ def test_transform_single_file(self): with open(plist_file, mode='rb') as pfile: exp = plistlib.load(pfile) - self.assertEqual(res, exp) \ No newline at end of file + self.assertEqual(res, exp)