]> source.dussan.org Git - sonarqube.git/blob
9de67f6b6100779434e63780fcc57a59ef900342
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2017 SonarSource SA
4  * mailto:info AT sonarsource DOT com
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 3 of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  */
20 package org.sonar.server.computation.task.projectanalysis.issue;
21
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.List;
25 import org.sonar.api.issue.Issue;
26 import org.sonar.api.rule.RuleKey;
27 import org.sonar.api.utils.log.Loggers;
28 import org.sonar.core.issue.DefaultIssue;
29 import org.sonar.core.issue.tracking.Input;
30 import org.sonar.core.issue.tracking.LazyInput;
31 import org.sonar.core.issue.tracking.LineHashSequence;
32 import org.sonar.core.util.CloseableIterator;
33 import org.sonar.db.protobuf.DbCommons;
34 import org.sonar.db.protobuf.DbIssues;
35 import org.sonar.scanner.protocol.Constants.Severity;
36 import org.sonar.scanner.protocol.output.ScannerReport;
37 import org.sonar.server.computation.task.projectanalysis.batch.BatchReportReader;
38 import org.sonar.server.computation.task.projectanalysis.component.Component;
39 import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolder;
40 import org.sonar.server.computation.task.projectanalysis.issue.commonrule.CommonRuleEngine;
41 import org.sonar.server.computation.task.projectanalysis.issue.filter.IssueFilter;
42 import org.sonar.server.computation.task.projectanalysis.source.SourceLinesRepository;
43 import org.sonar.server.rule.CommonRuleKeys;
44
45 import static com.google.common.collect.Lists.newArrayList;
46 import static org.apache.commons.lang.StringUtils.isNotEmpty;
47
48 public class TrackerRawInputFactory {
49
50   private final TreeRootHolder treeRootHolder;
51   private final BatchReportReader reportReader;
52   private final SourceLinesRepository sourceLinesRepository;
53   private final CommonRuleEngine commonRuleEngine;
54   private final IssueFilter issueFilter;
55
56   public TrackerRawInputFactory(TreeRootHolder treeRootHolder, BatchReportReader reportReader,
57     SourceLinesRepository sourceLinesRepository, CommonRuleEngine commonRuleEngine, IssueFilter issueFilter) {
58     this.treeRootHolder = treeRootHolder;
59     this.reportReader = reportReader;
60     this.sourceLinesRepository = sourceLinesRepository;
61     this.commonRuleEngine = commonRuleEngine;
62     this.issueFilter = issueFilter;
63   }
64
65   public Input<DefaultIssue> create(Component component) {
66     return new RawLazyInput(component);
67   }
68
69   private class RawLazyInput extends LazyInput<DefaultIssue> {
70     private final Component component;
71
72     private RawLazyInput(Component component) {
73       this.component = component;
74     }
75
76     @Override
77     protected LineHashSequence loadLineHashSequence() {
78       List<String> lines;
79       if (component.getType() == Component.Type.FILE) {
80         try (CloseableIterator<String> linesIt = sourceLinesRepository.readLines(component)) {
81           lines = newArrayList(linesIt);
82         }
83       } else {
84         lines = Collections.emptyList();
85       }
86       return LineHashSequence.createForLines(lines);
87     }
88
89     @Override
90     protected List<DefaultIssue> loadIssues() {
91       List<DefaultIssue> result = new ArrayList<>();
92
93       for (DefaultIssue commonRuleIssue : commonRuleEngine.process(component)) {
94         if (issueFilter.accept(commonRuleIssue, component)) {
95           result.add(init(commonRuleIssue));
96         }
97       }
98       try (CloseableIterator<ScannerReport.Issue> reportIssues = reportReader.readComponentIssues(component.getReportAttributes().getRef())) {
99         // optimization - do not load line hashes if there are no issues -> getLineHashSequence() is executed
100         // as late as possible
101         while (reportIssues.hasNext()) {
102           ScannerReport.Issue reportIssue = reportIssues.next();
103           if (!isIssueOnUnsupportedCommonRule(reportIssue)) {
104             Loggers.get(getClass()).debug("Ignored issue from analysis report on rule {}:{}", reportIssue.getRuleRepository(), reportIssue.getRuleKey());
105             continue;
106           }
107           DefaultIssue issue = toIssue(getLineHashSequence(), reportIssue);
108           if (issueFilter.accept(issue, component)) {
109             result.add(issue);
110           }
111         }
112       }
113
114       return result;
115     }
116
117     private boolean isIssueOnUnsupportedCommonRule(ScannerReport.Issue issue) {
118       // issues on batch common rules are ignored. This feature
119       // is natively supported by compute engine since 5.2.
120       return !issue.getRuleRepository().startsWith(CommonRuleKeys.REPOSITORY_PREFIX);
121     }
122
123     private DefaultIssue toIssue(LineHashSequence lineHashSeq, ScannerReport.Issue reportIssue) {
124       DefaultIssue issue = new DefaultIssue();
125       init(issue);
126       issue.setRuleKey(RuleKey.of(reportIssue.getRuleRepository(), reportIssue.getRuleKey()));
127       if (reportIssue.hasTextRange()) {
128         int startLine = reportIssue.getTextRange().getStartLine();
129         issue.setLine(startLine);
130         issue.setChecksum(lineHashSeq.getHashForLine(startLine));
131       } else {
132         issue.setChecksum("");
133       }
134       if (isNotEmpty(reportIssue.getMsg())) {
135         issue.setMessage(reportIssue.getMsg());
136       }
137       if (reportIssue.getSeverity() != Severity.UNSET_SEVERITY) {
138         issue.setSeverity(reportIssue.getSeverity().name());
139       }
140       if (reportIssue.getGap() != 0) {
141         issue.setGap(reportIssue.getGap());
142       }
143       DbIssues.Locations.Builder dbLocationsBuilder = DbIssues.Locations.newBuilder();
144       if (reportIssue.hasTextRange()) {
145         dbLocationsBuilder.setTextRange(convertTextRange(reportIssue.getTextRange()));
146       }
147       for (ScannerReport.Flow flow : reportIssue.getFlowList()) {
148         if (flow.getLocationCount() > 0) {
149           DbIssues.Flow.Builder dbFlowBuilder = DbIssues.Flow.newBuilder();
150           for (ScannerReport.IssueLocation location : flow.getLocationList()) {
151             dbFlowBuilder.addLocation(convertLocation(location));
152           }
153           dbLocationsBuilder.addFlow(dbFlowBuilder);
154         }
155       }
156       issue.setLocations(dbLocationsBuilder.build());
157       return issue;
158     }
159
160     private DefaultIssue init(DefaultIssue issue) {
161       issue.setResolution(null);
162       issue.setStatus(Issue.STATUS_OPEN);
163       issue.setComponentUuid(component.getUuid());
164       issue.setComponentKey(component.getKey());
165       issue.setProjectUuid(treeRootHolder.getRoot().getUuid());
166       issue.setProjectKey(treeRootHolder.getRoot().getKey());
167       return issue;
168     }
169
170     private DbIssues.Location convertLocation(ScannerReport.IssueLocation source) {
171       DbIssues.Location.Builder target = DbIssues.Location.newBuilder();
172       if (source.getComponentRef() != 0 && source.getComponentRef() != component.getReportAttributes().getRef()) {
173         target.setComponentId(treeRootHolder.getComponentByRef(source.getComponentRef()).getUuid());
174       }
175       if (isNotEmpty(source.getMsg())) {
176         target.setMsg(source.getMsg());
177       }
178       if (source.hasTextRange()) {
179         ScannerReport.TextRange sourceRange = source.getTextRange();
180         DbCommons.TextRange.Builder targetRange = convertTextRange(sourceRange);
181         target.setTextRange(targetRange);
182       }
183       return target.build();
184     }
185
186     private DbCommons.TextRange.Builder convertTextRange(ScannerReport.TextRange sourceRange) {
187       DbCommons.TextRange.Builder targetRange = DbCommons.TextRange.newBuilder();
188       targetRange.setStartLine(sourceRange.getStartLine());
189       targetRange.setStartOffset(sourceRange.getStartOffset());
190       targetRange.setEndLine(sourceRange.getEndLine());
191       targetRange.setEndOffset(sourceRange.getEndOffset());
192       return targetRange;
193     }
194   }
195 }