You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

AnalysisResult.java 9.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2022 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.scanner.mediumtest;
  21. import java.util.ArrayList;
  22. import java.util.Collection;
  23. import java.util.Collections;
  24. import java.util.HashMap;
  25. import java.util.List;
  26. import java.util.Map;
  27. import javax.annotation.CheckForNull;
  28. import org.slf4j.Logger;
  29. import org.slf4j.LoggerFactory;
  30. import org.sonar.api.batch.fs.InputComponent;
  31. import org.sonar.api.batch.fs.InputFile;
  32. import org.sonar.api.batch.fs.TextPointer;
  33. import org.sonar.api.batch.fs.TextRange;
  34. import org.sonar.api.batch.sensor.highlighting.TypeOfText;
  35. import org.sonar.api.batch.fs.internal.DefaultInputComponent;
  36. import org.sonar.api.batch.fs.internal.DefaultInputFile;
  37. import org.sonar.api.scanner.fs.InputProject;
  38. import org.sonar.core.util.CloseableIterator;
  39. import org.sonar.scanner.protocol.output.ScannerReport;
  40. import org.sonar.scanner.protocol.output.ScannerReport.Component;
  41. import org.sonar.scanner.protocol.output.ScannerReport.Symbol;
  42. import org.sonar.scanner.protocol.output.ScannerReportReader;
  43. import org.sonar.scanner.report.ReportPublisher;
  44. import org.sonar.scanner.report.ScannerReportUtils;
  45. import org.sonar.scanner.scan.SpringProjectScanContainer;
  46. import org.sonar.scanner.scan.filesystem.InputComponentStore;
  47. public class AnalysisResult implements AnalysisObserver {
  48. private static final Logger LOG = LoggerFactory.getLogger(AnalysisResult.class);
  49. private Map<String, InputFile> inputFilesByKeys = new HashMap<>();
  50. private InputProject project;
  51. private ScannerReportReader reader;
  52. @Override
  53. public void analysisCompleted(SpringProjectScanContainer container) {
  54. LOG.info("Store analysis results in memory for later assertions in medium test");
  55. ReportPublisher reportPublisher = container.getComponentByType(ReportPublisher.class);
  56. reader = new ScannerReportReader(reportPublisher.getReportDir().toFile());
  57. project = container.getComponentByType(InputProject.class);
  58. storeFs(container);
  59. }
  60. public ScannerReportReader getReportReader() {
  61. return reader;
  62. }
  63. private void storeFs(SpringProjectScanContainer container) {
  64. InputComponentStore inputFileCache = container.getComponentByType(InputComponentStore.class);
  65. for (InputFile inputPath : inputFileCache.inputFiles()) {
  66. inputFilesByKeys.put(((DefaultInputFile) inputPath).getProjectRelativePath(), inputPath);
  67. }
  68. }
  69. public Component getReportComponent(InputComponent inputComponent) {
  70. return getReportReader().readComponent(((DefaultInputComponent) inputComponent).scannerId());
  71. }
  72. public Component getReportComponent(int scannerId) {
  73. return getReportReader().readComponent(scannerId);
  74. }
  75. public List<ScannerReport.Issue> issuesFor(InputComponent inputComponent) {
  76. return issuesFor(((DefaultInputComponent) inputComponent).scannerId());
  77. }
  78. public List<ScannerReport.ExternalIssue> externalIssuesFor(InputComponent inputComponent) {
  79. return externalIssuesFor(((DefaultInputComponent) inputComponent).scannerId());
  80. }
  81. public List<ScannerReport.Issue> issuesFor(Component reportComponent) {
  82. int ref = reportComponent.getRef();
  83. return issuesFor(ref);
  84. }
  85. private List<ScannerReport.Issue> issuesFor(int ref) {
  86. List<ScannerReport.Issue> result = new ArrayList<>();
  87. try (CloseableIterator<ScannerReport.Issue> it = reader.readComponentIssues(ref)) {
  88. while (it.hasNext()) {
  89. result.add(it.next());
  90. }
  91. }
  92. return result;
  93. }
  94. private List<ScannerReport.ExternalIssue> externalIssuesFor(int ref) {
  95. List<ScannerReport.ExternalIssue> result = new ArrayList<>();
  96. try (CloseableIterator<ScannerReport.ExternalIssue> it = reader.readComponentExternalIssues(ref)) {
  97. while (it.hasNext()) {
  98. result.add(it.next());
  99. }
  100. }
  101. return result;
  102. }
  103. public InputProject project() {
  104. return project;
  105. }
  106. public Collection<InputFile> inputFiles() {
  107. return inputFilesByKeys.values();
  108. }
  109. @CheckForNull
  110. public InputFile inputFile(String relativePath) {
  111. return inputFilesByKeys.get(relativePath);
  112. }
  113. public Map<String, List<ScannerReport.Measure>> allMeasures() {
  114. Map<String, List<ScannerReport.Measure>> result = new HashMap<>();
  115. List<ScannerReport.Measure> projectMeasures = new ArrayList<>();
  116. try (CloseableIterator<ScannerReport.Measure> it = reader.readComponentMeasures(((DefaultInputComponent) project).scannerId())) {
  117. while (it.hasNext()) {
  118. projectMeasures.add(it.next());
  119. }
  120. }
  121. result.put(project.key(), projectMeasures);
  122. for (InputFile inputFile : inputFilesByKeys.values()) {
  123. List<ScannerReport.Measure> measures = new ArrayList<>();
  124. try (CloseableIterator<ScannerReport.Measure> it = reader.readComponentMeasures(((DefaultInputComponent) inputFile).scannerId())) {
  125. while (it.hasNext()) {
  126. measures.add(it.next());
  127. }
  128. }
  129. result.put(inputFile.key(), measures);
  130. }
  131. return result;
  132. }
  133. /**
  134. * Get highlighting types at a given position in an inputfile
  135. *
  136. * @param lineOffset 0-based offset in file
  137. */
  138. public List<TypeOfText> highlightingTypeFor(InputFile file, int line, int lineOffset) {
  139. int ref = ((DefaultInputComponent) file).scannerId();
  140. if (!reader.hasSyntaxHighlighting(ref)) {
  141. return Collections.emptyList();
  142. }
  143. TextPointer pointer = file.newPointer(line, lineOffset);
  144. List<TypeOfText> result = new ArrayList<>();
  145. try (CloseableIterator<ScannerReport.SyntaxHighlightingRule> it = reader.readComponentSyntaxHighlighting(ref)) {
  146. while (it.hasNext()) {
  147. ScannerReport.SyntaxHighlightingRule rule = it.next();
  148. TextRange ruleRange = toRange(file, rule.getRange());
  149. if (ruleRange.start().compareTo(pointer) <= 0 && ruleRange.end().compareTo(pointer) > 0) {
  150. result.add(ScannerReportUtils.toBatchType(rule.getType()));
  151. }
  152. }
  153. } catch (Exception e) {
  154. throw new IllegalStateException("Can't read syntax highlighting for " + file, e);
  155. }
  156. return result;
  157. }
  158. private static TextRange toRange(InputFile file, ScannerReport.TextRange reportRange) {
  159. return file.newRange(file.newPointer(reportRange.getStartLine(), reportRange.getStartOffset()), file.newPointer(reportRange.getEndLine(), reportRange.getEndOffset()));
  160. }
  161. /**
  162. * Get list of all start positions of a symbol in an inputfile
  163. *
  164. * @param symbolStartLine 0-based start offset for the symbol in file
  165. * @param symbolStartLineOffset 0-based end offset for the symbol in file
  166. */
  167. @CheckForNull
  168. public List<ScannerReport.TextRange> symbolReferencesFor(InputFile file, int symbolStartLine, int symbolStartLineOffset) {
  169. int ref = ((DefaultInputComponent) file).scannerId();
  170. try (CloseableIterator<Symbol> symbols = getReportReader().readComponentSymbols(ref)) {
  171. while (symbols.hasNext()) {
  172. Symbol symbol = symbols.next();
  173. if (symbol.getDeclaration().getStartLine() == symbolStartLine && symbol.getDeclaration().getStartOffset() == symbolStartLineOffset) {
  174. return symbol.getReferenceList();
  175. }
  176. }
  177. }
  178. return Collections.emptyList();
  179. }
  180. public List<ScannerReport.Duplication> duplicationsFor(InputFile file) {
  181. List<ScannerReport.Duplication> result = new ArrayList<>();
  182. int ref = ((DefaultInputComponent) file).scannerId();
  183. try (CloseableIterator<ScannerReport.Duplication> it = getReportReader().readComponentDuplications(ref)) {
  184. while (it.hasNext()) {
  185. result.add(it.next());
  186. }
  187. } catch (Exception e) {
  188. throw new IllegalStateException(e);
  189. }
  190. return result;
  191. }
  192. public List<ScannerReport.CpdTextBlock> duplicationBlocksFor(InputFile file) {
  193. List<ScannerReport.CpdTextBlock> result = new ArrayList<>();
  194. int ref = ((DefaultInputComponent) file).scannerId();
  195. try (CloseableIterator<ScannerReport.CpdTextBlock> it = getReportReader().readCpdTextBlocks(ref)) {
  196. while (it.hasNext()) {
  197. result.add(it.next());
  198. }
  199. } catch (Exception e) {
  200. throw new IllegalStateException(e);
  201. }
  202. return result;
  203. }
  204. @CheckForNull
  205. public ScannerReport.LineCoverage coverageFor(InputFile file, int line) {
  206. int ref = ((DefaultInputComponent) file).scannerId();
  207. try (CloseableIterator<ScannerReport.LineCoverage> it = getReportReader().readComponentCoverage(ref)) {
  208. while (it.hasNext()) {
  209. ScannerReport.LineCoverage coverage = it.next();
  210. if (coverage.getLine() == line) {
  211. return coverage;
  212. }
  213. }
  214. } catch (Exception e) {
  215. throw new IllegalStateException(e);
  216. }
  217. return null;
  218. }
  219. public List<ScannerReport.AdHocRule> adHocRules() {
  220. List<ScannerReport.AdHocRule> result = new ArrayList<>();
  221. try (CloseableIterator<ScannerReport.AdHocRule> it = getReportReader().readAdHocRules()) {
  222. while (it.hasNext()) {
  223. result.add(it.next());
  224. }
  225. } catch (Exception e) {
  226. throw new IllegalStateException(e);
  227. }
  228. return result;
  229. }
  230. }