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.

IssueExclusionsRegexpScanner.java 5.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2019 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.issue.ignore.scanner;
  21. import java.util.ArrayList;
  22. import java.util.HashSet;
  23. import java.util.List;
  24. import java.util.Set;
  25. import java.util.regex.Pattern;
  26. import org.apache.commons.lang.StringUtils;
  27. import org.sonar.api.batch.fs.internal.charhandler.CharHandler;
  28. import org.sonar.api.utils.log.Logger;
  29. import org.sonar.api.utils.log.Loggers;
  30. import org.sonar.scanner.issue.ignore.pattern.LineRange;
  31. import org.sonar.scanner.issue.ignore.pattern.PatternMatcher;
  32. import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader.DoubleRegexpMatcher;
  33. public class IssueExclusionsRegexpScanner extends CharHandler {
  34. private static final Logger LOG = Loggers.get(IssueExclusionsLoader.class);
  35. private final StringBuilder sb = new StringBuilder();
  36. private final List<Pattern> allFilePatterns;
  37. private final List<DoubleRegexpMatcher> blockMatchers;
  38. private final String componentKey;
  39. private final PatternMatcher patternMatcher;
  40. private int lineIndex = 1;
  41. private List<LineExclusion> lineExclusions = new ArrayList<>();
  42. private LineExclusion currentLineExclusion = null;
  43. private int fileLength = 0;
  44. private DoubleRegexpMatcher currentMatcher;
  45. IssueExclusionsRegexpScanner(String componentKey, List<Pattern> allFilePatterns, List<DoubleRegexpMatcher> blockMatchers, PatternMatcher patternMatcher) {
  46. this.allFilePatterns = allFilePatterns;
  47. this.blockMatchers = blockMatchers;
  48. this.patternMatcher = patternMatcher;
  49. this.componentKey = componentKey;
  50. String relativePath = StringUtils.substringAfterLast(componentKey, ":");
  51. LOG.info("'{}' generating issue exclusions", relativePath);
  52. }
  53. @Override
  54. public void handleIgnoreEoL(char c) {
  55. sb.append(c);
  56. }
  57. @Override
  58. public void newLine() {
  59. processLine(sb.toString());
  60. sb.setLength(0);
  61. lineIndex++;
  62. }
  63. @Override
  64. public void eof() {
  65. processLine(sb.toString());
  66. if (currentMatcher != null && !currentMatcher.hasSecondPattern()) {
  67. // this will happen when there is a start block regexp but no end block regexp
  68. endExclusion(lineIndex + 1);
  69. }
  70. // now create the new line-based pattern for this file if there are exclusions
  71. fileLength = lineIndex;
  72. if (!lineExclusions.isEmpty()) {
  73. Set<LineRange> lineRanges = convertLineExclusionsToLineRanges();
  74. LOG.debug("- Line exclusions found: {}", lineRanges);
  75. patternMatcher.addPatternToExcludeLines(componentKey, lineRanges);
  76. }
  77. }
  78. private void processLine(String line) {
  79. if (line.trim().length() == 0) {
  80. return;
  81. }
  82. // first check the single regexp patterns that can be used to totally exclude a file
  83. for (Pattern pattern : allFilePatterns) {
  84. if (pattern.matcher(line).find()) {
  85. patternMatcher.addPatternToExcludeResource(componentKey);
  86. // nothing more to do on this file
  87. LOG.debug("- Exclusion pattern '{}': every issue in this file will be ignored.", pattern);
  88. return;
  89. }
  90. }
  91. // then check the double regexps if we're still here
  92. checkDoubleRegexps(line, lineIndex);
  93. }
  94. private Set<LineRange> convertLineExclusionsToLineRanges() {
  95. Set<LineRange> lineRanges = new HashSet<>(lineExclusions.size());
  96. for (LineExclusion lineExclusion : lineExclusions) {
  97. lineRanges.add(lineExclusion.toLineRange(fileLength));
  98. }
  99. return lineRanges;
  100. }
  101. private void checkDoubleRegexps(String line, int lineIndex) {
  102. if (currentMatcher == null) {
  103. for (DoubleRegexpMatcher matcher : blockMatchers) {
  104. if (matcher.matchesFirstPattern(line)) {
  105. startExclusion(lineIndex);
  106. currentMatcher = matcher;
  107. break;
  108. }
  109. }
  110. } else {
  111. if (currentMatcher.matchesSecondPattern(line)) {
  112. endExclusion(lineIndex);
  113. currentMatcher = null;
  114. }
  115. }
  116. }
  117. private void startExclusion(int lineIndex) {
  118. currentLineExclusion = new LineExclusion(lineIndex);
  119. lineExclusions.add(currentLineExclusion);
  120. }
  121. private void endExclusion(int lineIndex) {
  122. currentLineExclusion.setEnd(lineIndex);
  123. currentLineExclusion = null;
  124. }
  125. private static class LineExclusion {
  126. private int start;
  127. private int end;
  128. LineExclusion(int start) {
  129. this.start = start;
  130. this.end = -1;
  131. }
  132. void setEnd(int end) {
  133. this.end = end;
  134. }
  135. public LineRange toLineRange(int fileLength) {
  136. return new LineRange(start, end == -1 ? fileLength : end);
  137. }
  138. }
  139. }