/*
* SonarQube
* Copyright (C) 2009-2017 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.scanner.scan.report;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import javax.annotation.Nullable;
import org.sonar.api.batch.fs.InputComponent;
import org.sonar.api.batch.fs.InputDir;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.InputModule;
import org.sonar.api.batch.fs.InputPath;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.rule.Rule;
import org.sonar.api.rules.RulePriority;
import org.sonar.scanner.issue.tracking.TrackedIssue;
public final class ResourceReport {
private final InputComponent component;
private final IssueVariation total = new IssueVariation();
private final Map<ReportRuleKey, RuleReport> ruleReportByRuleKey = new HashMap<>();
private List<TrackedIssue> issues = new ArrayList<>();
private Map<Integer, List<TrackedIssue>> issuesPerLine = new HashMap<>();
private Map<Integer, List<TrackedIssue>> newIssuesPerLine = new HashMap<>();
private Map<Rule, AtomicInteger> issuesByRule = new HashMap<>();
private Map<RulePriority, AtomicInteger> issuesBySeverity = new EnumMap<>(RulePriority.class);
public ResourceReport(InputComponent component) {
this.component = component;
}
public InputComponent getResourceNode() {
return component;
}
public String getName() {
if (component instanceof InputPath) {
InputPath inputPath = (InputPath) component;
return inputPath.path().getFileName().toString();
} else if (component instanceof InputModule) {
DefaultInputModule module = (DefaultInputModule) component;
return module.definition().getName();
}
throw new IllegalStateException("Unknown component type: " + component.getClass());
}
public String getKey() {
return component.key();
}
/**
* Must match one of the png in the resources, under org/scanner/scan/report/issuesreport_files
*/
public String getType() {
if (component instanceof InputFile) {
return "FIL";
} else if (component instanceof InputDir) {
return "DIR";
} else if (component instanceof InputModule) {
return "PRJ";
}
throw new IllegalStateException("Unknown component type: " + component.getClass());
}
public IssueVariation getTotal() {
return total;
}
public List<TrackedIssue> getIssues() {
return issues;
}
public Map<Integer, List<TrackedIssue>> getIssuesPerLine() {
return issuesPerLine;
}
public List<TrackedIssue> getIssuesAtLine(int lineId, boolean all) {
if (all) {
if (issuesPerLine.containsKey(lineId)) {
return issuesPerLine.get(lineId);
}
} else if (newIssuesPerLine.containsKey(lineId)) {
return newIssuesPerLine.get(lineId);
}
return Collections.emptyList();
}
public void addIssue(TrackedIssue issue, Rule rule, RulePriority severity) {
ReportRuleKey reportRuleKey = new ReportRuleKey(rule, severity);
initMaps(reportRuleKey);
issues.add(issue);
Integer line = issue.startLine();
line = line != null ? line : 0;
if (!issuesPerLine.containsKey(line)) {
issuesPerLine.put(line, new ArrayList<TrackedIssue>());
}
issuesPerLine.get(line).add(issue);
if (!issuesByRule.containsKey(rule)) {
issuesByRule.put(rule, new AtomicInteger());
}
issuesByRule.get(rule).incrementAndGet();
if (!issuesBySeverity.containsKey(severity)) {
issuesBySeverity.put(severity, new AtomicInteger());
}
issuesBySeverity.get(severity).incrementAndGet();
ruleReportByRuleKey.get(reportRuleKey).getTotal().incrementCountInCurrentAnalysis();
total.incrementCountInCurrentAnalysis();
if (issue.isNew()) {
if (!newIssuesPerLine.containsKey(line)) {
newIssuesPerLine.put(line, new ArrayList<TrackedIssue>());
}
newIssuesPerLine.get(line).add(issue);
total.incrementNewIssuesCount();
ruleReportByRuleKey.get(reportRuleKey).getTotal().incrementNewIssuesCount();
}
}
public void addResolvedIssue(Rule rule, RulePriority severity) {
ReportRuleKey reportRuleKey = new ReportRuleKey(rule, severity);
initMaps(reportRuleKey);
total.incrementResolvedIssuesCount();
ruleReportByRuleKey.get(reportRuleKey).getTotal().incrementResolvedIssuesCount();
}
private void initMaps(ReportRuleKey reportRuleKey) {
if (!ruleReportByRuleKey.containsKey(reportRuleKey)) {
ruleReportByRuleKey.put(reportRuleKey, new RuleReport(reportRuleKey));
}
}
public boolean isDisplayableLine(@Nullable Integer lineNumber, boolean all) {
if (lineNumber == null || lineNumber < 1) {
return false;
}
for (int i = lineNumber - 2; i <= lineNumber + 2; i++) {
if (hasIssues(i, all)) {
return true;
}
}
return false;
}
private boolean hasIssues(Integer lineId, boolean all) {
if (all) {
List<TrackedIssue> issuesAtLine = issuesPerLine.get(lineId);
return issuesAtLine != null && !issuesAtLine.isEmpty();
}
List<TrackedIssue> newIssuesAtLine = newIssuesPerLine.get(lineId);
return newIssuesAtLine != null && !newIssuesAtLine.isEmpty();
}
public List<RuleReport> getRuleReports() {
List<RuleReport> result = new ArrayList<>(ruleReportByRuleKey.values());
Collections.sort(result, new RuleReportComparator());
return result;
}
}