Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[report-converter] Support Roslynator #3765

Merged
merged 13 commits into from
Oct 24, 2022
Merged
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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) |
Expand Down
1 change: 1 addition & 0 deletions docs/supported_code_analyzers.md
Original file line number Diff line number Diff line change
Expand Up @@ -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) | ✓ |
Expand Down
35 changes: 34 additions & 1 deletion docs/tools/report-converter.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ a CodeChecker server.
* [Sphinx](#sphinx)
* [Sparse](#sparse)
* [cpplint](#cpplint)
* [Roslynator.DotNet.Cli](#roslynatordotnetcli)
* [Plist to html tool](#plist-to-html-tool)
* [Usage](#usage-1)
* [Report hash generation module](#report-hash-generation-module)
Expand Down Expand Up @@ -72,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
Expand Down Expand Up @@ -112,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
Expand Down Expand Up @@ -585,6 +587,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 [.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
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.

```sh
# Change directory to your project
cd path/to/your/project_or_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
report-converter -t roslynator -o ./codechecker_roslynator_reports ./sample.xml

# Store the Roslynator report 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.
Expand Down
Original file line number Diff line number Diff line change
@@ -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
#
# -------------------------------------------------------------------------
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# -------------------------------------------------------------------------
#
# 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.DotNet.Cli'
URL = 'https://github.com/JosefPihrt/Roslynator' \
+ '#roslynator-command-line-tool-'

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)
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,
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.attrib.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),
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.attrib.get('Line')
column = location.attrib.get('Character')

return Report(
get_or_create_file(source_file_path, self.__file_cache),
int(line),
int(column),
message,
id
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
all:
roslynator analyze files/files.csproj --output out.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>diagnostics</key>
<array>
<dict>
<key>category</key>
<string>unknown</string>
<key>check_name</key>
<string>CA1806</string>
<key>description</key>
<string>Do not ignore method results</string>
<key>issue_hash_content_of_line_in_context</key>
<string>70e00602407f8f0820dad202635fd677</string>
<key>location</key>
<dict>
<key>col</key>
<integer>9</integer>
<key>file</key>
<integer>0</integer>
<key>line</key>
<integer>17</integer>
</dict>
<key>path</key>
<array>
<dict>
<key>depth</key>
<integer>0</integer>
<key>kind</key>
<string>event</string>
<key>location</key>
<dict>
<key>col</key>
<integer>9</integer>
<key>file</key>
<integer>0</integer>
<key>line</key>
<integer>17</integer>
</dict>
<key>message</key>
<string>Do not ignore method results</string>
</dict>
</array>
<key>type</key>
<string>roslynator</string>
</dict>
<dict>
<key>category</key>
<string>unknown</string>
<key>check_name</key>
<string>CA1822</string>
<key>description</key>
<string>Mark members as static</string>
<key>issue_hash_content_of_line_in_context</key>
<string>057dcbd39881ede94293d9a9048304ac</string>
<key>location</key>
<dict>
<key>col</key>
<integer>16</integer>
<key>file</key>
<integer>0</integer>
<key>line</key>
<integer>9</integer>
</dict>
<key>path</key>
<array>
<dict>
<key>depth</key>
<integer>0</integer>
<key>kind</key>
<string>event</string>
<key>location</key>
<dict>
<key>col</key>
<integer>16</integer>
<key>file</key>
<integer>0</integer>
<key>line</key>
<integer>9</integer>
</dict>
<key>message</key>
<string>Mark members as static</string>
</dict>
</array>
<key>type</key>
<string>roslynator</string>
</dict>
</array>
<key>files</key>
<array>
<string>files/Sample.cs</string>
</array>
<key>metadata</key>
<dict>
<key>analyzer</key>
<dict>
<key>name</key>
<string>roslynator</string>
</dict>
<key>generated_by</key>
<dict>
<key>name</key>
<string>report-converter</string>
<key>version</key>
<string>x.y.z</string>
</dict>
</dict>
</dict>
</plist>
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
bin/
obj/
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System.Collections.Generic;
using System.Linq;

namespace files;

public class Sample
{
// Triggers CA1822
public int Add(int a, int b)
{
return a + b;
}

// Triggers CA1806
public void AddOne(IEnumerable<int> enumerable)
{
enumerable.Select(n => Add(1, n));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>enable</Nullable>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
</PropertyGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<Roslynator>
<CodeAnalysis>
<Summary>
<Diagnostic Id="CA1014" Title="Mark assemblies with CLSCompliant" Count="1" />
<Diagnostic Id="CA1806" Title="Do not ignore method results" Count="1" />
<Diagnostic Id="CA1822" Title="Mark members as static" Count="1" />
</Summary>
<Projects>
<Project Name="files" FilePath="files/files.csproj">
<Diagnostics>
<Diagnostic Id="CA1014">
<Severity>Warning</Severity>
<Message>Mark assemblies with CLSCompliant</Message>
</Diagnostic>
<Diagnostic Id="CA1806">
<Severity>Warning</Severity>
<Message>Do not ignore method results</Message>
<FilePath>files/Sample.cs</FilePath>
<Location Line="17" Character="9" />
</Diagnostic>
<Diagnostic Id="CA1822">
<Severity>Warning</Severity>
<Message>Mark members as static</Message>
<FilePath>files/Sample.cs</FilePath>
<Location Line="9" Character="16" />
</Diagnostic>
</Diagnostics>
</Project>
</Projects>
</CodeAnalysis>
</Roslynator>
Loading