D-Scanner/src/dscanner/reports.d

245 lines
4.9 KiB
D

// Copyright Brian Schott (Hackerpilot) 2012.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
module dscanner.reports;
import std.json;
import std.algorithm : map;
import std.array : split, array, Appender, appender;
import dscanner.analysis.base : Message, MessageSet;
import dscanner.analysis.stats_collector;
class DScannerJsonReporter
{
struct Issue
{
Message message;
string type;
}
private Appender!(Issue[]) _issues;
this()
{
_issues = appender!(Issue[]);
}
void addMessageSet(MessageSet messageSet)
{
_issues ~= toIssues(messageSet);
}
void addMessage(Message message, bool isError = false)
{
_issues ~= toIssue(message, isError);
}
string getContent(StatsCollector stats, ulong lineOfCodeCount)
{
JSONValue result = [
"issues" : JSONValue(_issues.data.map!(e => toJson(e)).array),
"interfaceCount": JSONValue(stats.interfaceCount),
"classCount": JSONValue(stats.classCount),
"functionCount": JSONValue(stats.functionCount),
"templateCount": JSONValue(stats.templateCount),
"structCount": JSONValue(stats.structCount),
"statementCount": JSONValue(stats.statementCount),
"lineOfCodeCount": JSONValue(lineOfCodeCount),
"undocumentedPublicSymbols": JSONValue(stats.undocumentedPublicSymbols)
];
return result.toPrettyString();
}
private static JSONValue toJson(Issue issue)
{
// dfmt off
JSONValue js = JSONValue([
"key": JSONValue(issue.message.key),
"fileName": JSONValue(issue.message.fileName),
"line": JSONValue(issue.message.line),
"column": JSONValue(issue.message.column),
"message": JSONValue(issue.message.message),
"type": JSONValue(issue.type)
]);
// dfmt on
if (issue.message.checkName !is null)
{
js["name"] = JSONValue(issue.message.checkName);
}
return js;
}
private static Issue[] toIssues(MessageSet messageSet)
{
return messageSet[].map!(e => toIssue(e)).array;
}
private static Issue toIssue(Message message, bool isError = false)
{
// dfmt off
Issue issue = {
message: message,
type : isError ? "error" : "warn"
};
// dfmt on
return issue;
}
}
class SonarQubeGenericIssueDataReporter
{
enum Type
{
bug = "BUG",
vulnerability = "VULNERABILITY",
codeSmell = "CODE_SMELL"
}
enum Severity
{
blocker = "BLOCKER",
critical = "CRITICAL",
major = "MAJOR",
minor = "MINOR",
info = "INFO"
}
struct Issue
{
string engineId;
string ruleId;
Location primaryLocation;
string type;
string severity;
int effortMinutes;
Location[] secondaryLocations;
}
struct Location
{
string message;
string filePath;
TextRange textRange;
}
struct TextRange
{
// SonarQube Generic Issue only allows specifying start line only
// or the complete range, for which start and end has to differ
// D-Scanner does not provide the complete range info
long startLine;
}
private Appender!(Issue[]) _issues;
this()
{
_issues = appender!(Issue[]);
}
void addMessageSet(MessageSet messageSet)
{
_issues ~= toIssues(messageSet);
}
void addMessage(Message message, bool isError = false)
{
_issues ~= toIssue(message, isError);
}
string getContent()
{
JSONValue result = [
"issues" : JSONValue(_issues.data.map!(e => toJson(e)).array)
];
return result.toPrettyString();
}
private static JSONValue toJson(Issue issue)
{
// dfmt off
return JSONValue([
"engineId": JSONValue(issue.engineId),
"ruleId": JSONValue(issue.ruleId),
"severity": JSONValue(issue.severity),
"type": JSONValue(issue.type),
"primaryLocation": JSONValue([
"message": JSONValue(issue.primaryLocation.message),
"filePath": JSONValue(issue.primaryLocation.filePath),
"textRange": JSONValue([
"startLine": JSONValue(issue.primaryLocation.textRange.startLine)
]),
]),
]);
// dfmt on
}
private static Issue[] toIssues(MessageSet messageSet)
{
return messageSet[].map!(e => toIssue(e)).array;
}
private static Issue toIssue(Message message, bool isError = false)
{
// dfmt off
Issue issue = {
engineId: "dscanner",
ruleId : message.key,
severity : (isError) ? Severity.blocker : getSeverity(message.key),
type : getType(message.key),
primaryLocation : getPrimaryLocation(message)
};
// dfmt on
return issue;
}
private static Location getPrimaryLocation(Message message)
{
return Location(message.message, message.fileName, TextRange(message.line));
}
private static string getSeverity(string key)
{
auto a = key.split(".");
if (a.length <= 1)
{
return Severity.major;
}
else
{
switch (a[1])
{
case "style":
return Severity.minor;
default:
return Severity.major;
}
}
}
private static string getType(string key)
{
auto a = key.split(".");
if (a.length <= 1)
{
return Type.bug;
}
else
{
switch (a[1])
{
case "style":
return Type.codeSmell;
default:
return Type.bug;
}
}
}
}