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