]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-9025 Optimize computation issue exclusions
authorDuarte Meneses <duarte.meneses@sonarsource.com>
Wed, 5 Apr 2017 12:21:53 +0000 (14:21 +0200)
committerdbmeneses <duarte.meneses@sonarsource.com>
Tue, 11 Apr 2017 11:39:57 +0000 (13:39 +0200)
37 files changed:
it/it-tests/src/test/java/it/analysisExclusion/IssueExclusionsTest.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/FileMetadata.java
sonar-plugin-api/src/main/java/org/sonar/api/scan/issue/filter/FilterableIssue.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ModuleIssues.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/EnforceIssuesFilter.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/IgnoreIssuesFilter.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/AbstractPatternInitializer.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/BlockIssuePattern.java [new file with mode: 0644]
sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssueExclusionPatternInitializer.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssueInclusionPatternInitializer.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssuePattern.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/LineRange.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/PatternDecoder.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/PatternMatcher.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsLoader.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScanner.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/AbstractPhaseExecutor.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/IssuesPhaseExecutor.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/PublishPhaseExecutor.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleScanContainer.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/MetadataGenerator.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/MetadataGeneratorProvider.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ModuleIssuesTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/EnforceIssuesFilterTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/IgnoreIssuesFilterTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/IssueExclusionPatternInitializerTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/IssueInclusionPatternInitializerTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/IssuePatternTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/PatternDecoderTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/PatternMatcherTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsLoaderTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScannerTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/fs/FileSystemMediumTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/MetadataGeneratorProviderTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/MetadataGeneratorTest.java
sonar-scanner-engine/src/test/resources/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScannerTest/file-with-single-regexp-last-line.txt [new file with mode: 0644]
sonar-scanner-engine/src/test/resources/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScannerTest/file-with-single-regexp.txt

index 42e9951edeff0b663892f6efcfe28870ebdff86a..46292024bd5ec19d1bc8e679d18f8fce6e72bada 100644 (file)
@@ -258,6 +258,6 @@ public class IssueExclusionsTest {
   private void checkAnalysisFails(String... properties) {
     BuildResult buildResult = scan(properties);
     assertThat(buildResult.getStatus()).isNotEqualTo(0);
-    assertThat(buildResult.getLogs().indexOf("SonarException")).isGreaterThan(0);
+    assertThat(buildResult.getLogs().indexOf("IllegalStateException")).isGreaterThan(0);
   }
 }
index cf962b2c79674a1a4da0416d9be13892a2e43c8d..4ddcf1d8d4e67a082bc8491918544c32e55acf31 100644 (file)
@@ -33,8 +33,10 @@ import java.nio.charset.CharsetEncoder;
 import java.nio.charset.CodingErrorAction;
 import java.nio.charset.StandardCharsets;
 import java.security.MessageDigest;
+
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
+
 import org.apache.commons.codec.binary.Hex;
 import org.apache.commons.codec.digest.DigestUtils;
 import org.apache.commons.io.ByteOrderMark;
@@ -270,15 +272,26 @@ public class FileMetadata {
    * Compute hash of a file ignoring line ends differences.
    * Maximum performance is needed.
    */
-  public Metadata readMetadata(File file, Charset encoding) {
+  public Metadata readMetadata(File file, Charset encoding, @Nullable CharHandler otherHandler) {
     LineCounter lineCounter = new LineCounter(file, encoding);
     FileHashComputer fileHashComputer = new FileHashComputer(file);
     LineOffsetCounter lineOffsetCounter = new LineOffsetCounter();
-    readFile(file, encoding, lineCounter, fileHashComputer, lineOffsetCounter);
+
+    if (otherHandler != null) {
+      CharHandler[] handlers = {lineCounter, fileHashComputer, lineOffsetCounter, otherHandler};
+      readFile(file, encoding, handlers);
+    } else {
+      CharHandler[] handlers = {lineCounter, fileHashComputer, lineOffsetCounter};
+      readFile(file, encoding, handlers);
+    }
     return new Metadata(lineCounter.lines(), lineCounter.nonBlankLines(), fileHashComputer.getHash(), lineOffsetCounter.getOriginalLineOffsets(),
       lineOffsetCounter.getLastValidOffset());
   }
 
+  public Metadata readMetadata(File file, Charset encoding) {
+    return readMetadata(file, encoding, null);
+  }
+
   /**
    * For testing purpose
    */
@@ -286,16 +299,18 @@ public class FileMetadata {
     LineCounter lineCounter = new LineCounter(new File("fromString"), StandardCharsets.UTF_16);
     FileHashComputer fileHashComputer = new FileHashComputer(new File("fromString"));
     LineOffsetCounter lineOffsetCounter = new LineOffsetCounter();
+    CharHandler[] handlers = {lineCounter, fileHashComputer, lineOffsetCounter};
+
     try {
-      read(reader, lineCounter, fileHashComputer, lineOffsetCounter);
+      read(reader, handlers);
     } catch (IOException e) {
-      throw new IllegalStateException("Should never occurs", e);
+      throw new IllegalStateException("Should never occur", e);
     }
     return new Metadata(lineCounter.lines(), lineCounter.nonBlankLines(), fileHashComputer.getHash(), lineOffsetCounter.getOriginalLineOffsets(),
       lineOffsetCounter.getLastValidOffset());
   }
 
-  public static void readFile(File file, Charset encoding, CharHandler... handlers) {
+  public static void readFile(File file, Charset encoding, CharHandler[] handlers) {
     try (BOMInputStream bomIn = new BOMInputStream(new FileInputStream(file),
       ByteOrderMark.UTF_8, ByteOrderMark.UTF_16LE, ByteOrderMark.UTF_16BE, ByteOrderMark.UTF_32LE, ByteOrderMark.UTF_32BE);
       Reader reader = new BufferedReader(new InputStreamReader(bomIn, encoding))) {
@@ -305,7 +320,7 @@ public class FileMetadata {
     }
   }
 
-  private static void read(Reader reader, CharHandler... handlers) throws IOException {
+  private static void read(Reader reader, CharHandler[] handlers) throws IOException {
     char c;
     int i = reader.read();
     boolean afterCR = false;
@@ -354,15 +369,13 @@ public class FileMetadata {
 
   @FunctionalInterface
   public interface LineHashConsumer {
-
     void consume(int lineIdx, @Nullable byte[] hash);
-
   }
 
   /**
    * Compute a MD5 hash of each line of the file after removing of all blank chars
    */
   public static void computeLineHashesForIssueTracking(InputFile f, LineHashConsumer consumer) {
-    readFile(f.file(), f.charset(), new LineHashComputer(consumer, f.file()));
+    readFile(f.file(), f.charset(), new CharHandler[] {new LineHashComputer(consumer, f.file())});
   }
 }
index 2068d49a24b73490367bec3f62bc8dc02554f1d9..6928b75e036854eeea56bff6da1bea4047b2f10a 100644 (file)
@@ -20,6 +20,9 @@
 package org.sonar.api.scan.issue.filter;
 
 import java.util.Date;
+
+import javax.annotation.CheckForNull;
+
 import org.sonar.api.rule.RuleKey;
 
 /**
@@ -35,6 +38,7 @@ public interface FilterableIssue {
 
   String message();
 
+  @CheckForNull
   Integer line();
 
   /**
@@ -46,6 +50,7 @@ public interface FilterableIssue {
   /**
    * @since 5.5
    */
+  @CheckForNull
   Double gap();
 
   Date creationDate();
index 5e34e44d6be68a6e48ef5f0facca7ea4d5b9d0a6..958b1e6384389425813be72862f965ff99d58a74 100644 (file)
@@ -21,7 +21,6 @@ package org.sonar.scanner.issue;
 
 import com.google.common.base.Strings;
 
-import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.batch.fs.TextRange;
 import org.sonar.api.batch.fs.internal.DefaultInputComponent;
 import org.sonar.api.batch.rule.ActiveRule;
@@ -32,7 +31,6 @@ import org.sonar.api.batch.sensor.issue.Issue;
 import org.sonar.api.batch.sensor.issue.Issue.Flow;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.utils.MessageException;
-import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
 import org.sonar.scanner.protocol.Constants.Severity;
 import org.sonar.scanner.protocol.output.ScannerReport;
 import org.sonar.scanner.protocol.output.ScannerReport.IssueLocation;
@@ -47,14 +45,12 @@ public class ModuleIssues {
   private final Rules rules;
   private final IssueFilters filters;
   private final ReportPublisher reportPublisher;
-  private final IssueExclusionsLoader issueExclusionsLoader;
 
-  public ModuleIssues(ActiveRules activeRules, Rules rules, IssueFilters filters, ReportPublisher reportPublisher, IssueExclusionsLoader issueExclusionsLoader) {
+  public ModuleIssues(ActiveRules activeRules, Rules rules, IssueFilters filters, ReportPublisher reportPublisher) {
     this.activeRules = activeRules;
     this.rules = rules;
     this.filters = filters;
     this.reportPublisher = reportPublisher;
-    this.issueExclusionsLoader = issueExclusionsLoader;
   }
 
   public boolean initAndAddIssue(Issue issue) {
@@ -93,13 +89,6 @@ public class ModuleIssues {
     applyFlows(builder, locationBuilder, textRangeBuilder, issue);
     ScannerReport.Issue rawIssue = builder.build();
 
-    if (issueExclusionsLoader.shouldExecute() && inputComponent.isFile()) {
-      InputFile inputFile = (InputFile) inputComponent;
-      if (!issueExclusionsLoader.isLoaded(inputFile)) {
-        issueExclusionsLoader.loadFile(inputFile);
-      }
-    }
-
     if (filters.accept(inputComponent.key(), rawIssue)) {
       write(inputComponent.batchId(), rawIssue);
       return true;
index b22aa81a5164c23cf972ad27e3cd981000c5e526..5c6e4caf4096704c2fe6878b67f55b756cdc38f8 100644 (file)
  */
 package org.sonar.scanner.issue.ignore;
 
+import org.sonar.api.batch.fs.InputComponent;
+import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.scan.issue.filter.FilterableIssue;
+
+import javax.annotation.CheckForNull;
+
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.sonar.api.scan.issue.filter.IssueFilter;
 import org.sonar.api.scan.issue.filter.IssueFilterChain;
 import org.sonar.scanner.issue.ignore.pattern.IssueInclusionPatternInitializer;
 import org.sonar.scanner.issue.ignore.pattern.IssuePattern;
+import org.sonar.scanner.scan.filesystem.InputComponentStore;
 
 public class EnforceIssuesFilter implements IssueFilter {
+  private static final Logger LOG = LoggerFactory.getLogger(EnforceIssuesFilter.class);
 
   private IssueInclusionPatternInitializer patternInitializer;
+  private InputComponentStore componentStore;
 
-  private static final Logger LOG = LoggerFactory.getLogger(EnforceIssuesFilter.class);
-
-  public EnforceIssuesFilter(IssueInclusionPatternInitializer patternInitializer) {
+  public EnforceIssuesFilter(IssueInclusionPatternInitializer patternInitializer, InputComponentStore componentStore) {
     this.patternInitializer = patternInitializer;
+    this.componentStore = componentStore;
   }
 
   @Override
@@ -46,8 +53,8 @@ public class EnforceIssuesFilter implements IssueFilter {
     for (IssuePattern pattern : patternInitializer.getMulticriteriaPatterns()) {
       if (pattern.getRulePattern().match(issue.ruleKey().toString())) {
         atLeastOneRuleMatched = true;
-        String pathForComponent = patternInitializer.getPathForComponent(issue.componentKey());
-        if (pathForComponent != null && pattern.getResourcePattern().match(pathForComponent)) {
+        String relativePath = getRelativePath(issue.componentKey());
+        if (relativePath != null && pattern.getResourcePattern().match(relativePath)) {
           atLeastOnePatternFullyMatched = true;
           matchingPattern = pattern;
         }
@@ -63,4 +70,14 @@ public class EnforceIssuesFilter implements IssueFilter {
       return chain.accept(issue);
     }
   }
+
+  @CheckForNull
+  private String getRelativePath(String componentKey) {
+    InputComponent component = componentStore.getByKey(componentKey);
+    if (component == null || !component.isFile()) {
+      return null;
+    }
+    InputFile inputPath = (InputFile) component;
+    return inputPath.relativePath();
+  }
 }
index 0eaf1193cb6cbbbd030ec7f7d8236c285a722511..0c543eab505b73f2a8f02135ba3a1ae977fcb0f1 100644 (file)
@@ -24,7 +24,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.sonar.api.scan.issue.filter.IssueFilter;
 import org.sonar.api.scan.issue.filter.IssueFilterChain;
-import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer;
 import org.sonar.scanner.issue.ignore.pattern.IssuePattern;
 import org.sonar.scanner.issue.ignore.pattern.PatternMatcher;
 
@@ -34,8 +33,8 @@ public class IgnoreIssuesFilter implements IssueFilter {
 
   private static final Logger LOG = LoggerFactory.getLogger(IgnoreIssuesFilter.class);
 
-  public IgnoreIssuesFilter(IssueExclusionPatternInitializer patternInitializer) {
-    this.patternMatcher = patternInitializer.getPatternMatcher();
+  public IgnoreIssuesFilter(PatternMatcher patternMatcher) {
+    this.patternMatcher = patternMatcher;
   }
 
   @Override
@@ -48,7 +47,7 @@ public class IgnoreIssuesFilter implements IssueFilter {
   }
 
   private boolean hasMatchFor(FilterableIssue issue) {
-    IssuePattern pattern = patternMatcher.getMatchingPattern(issue);
+    IssuePattern pattern = patternMatcher.getMatchingPattern(issue.componentKey(), issue.ruleKey(), issue.line());
     if (pattern != null) {
       logExclusion(issue, pattern);
       return true;
index 765085967d613c2e2661ba811cdbc1a919c8b2ef..b77a921e27f7a0600bce930ef3ef96b79187ed38 100644 (file)
@@ -26,14 +26,13 @@ import org.sonar.api.config.Settings;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Set;
 
 import static com.google.common.base.MoreObjects.firstNonNull;
 
 @ScannerSide
 public abstract class AbstractPatternInitializer {
-
   private Settings settings;
-
   private List<IssuePattern> multicriteriaPatterns;
 
   protected AbstractPatternInitializer(Settings settings) {
@@ -57,8 +56,6 @@ public abstract class AbstractPatternInitializer {
     return !multicriteriaPatterns.isEmpty();
   }
 
-  public abstract void initializePatternsForPath(String relativePath, String componentKey);
-
   @VisibleForTesting
   protected final void initPatterns() {
     // Patterns Multicriteria
@@ -71,8 +68,9 @@ public abstract class AbstractPatternInitializer {
       String lineRange = "*";
       String[] fields = new String[] {resourceKeyPattern, ruleKeyPattern, lineRange};
       PatternDecoder.checkRegularLineConstraints(StringUtils.join(fields, ","), fields);
-      IssuePattern pattern = new IssuePattern(firstNonNull(resourceKeyPattern, "*"), firstNonNull(ruleKeyPattern, "*"));
-      PatternDecoder.decodeRangeOfLines(pattern, firstNonNull(lineRange, "*"));
+      Set<LineRange> rangeOfLines = PatternDecoder.decodeRangeOfLines(firstNonNull(lineRange, "*"));
+      IssuePattern pattern = new IssuePattern(firstNonNull(resourceKeyPattern, "*"), firstNonNull(ruleKeyPattern, "*"), rangeOfLines);
+
       multicriteriaPatterns.add(pattern);
     }
   }
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/BlockIssuePattern.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/BlockIssuePattern.java
new file mode 100644 (file)
index 0000000..e221a70
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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.issue.ignore.pattern;
+
+public class BlockIssuePattern {
+  private String beginBlockRegexp;
+  private String endBlockRegexp;
+
+  public BlockIssuePattern(String beginBlockRegexp, String endBlockRegexp) {
+    this.beginBlockRegexp = beginBlockRegexp;
+    this.endBlockRegexp = endBlockRegexp;
+  }
+
+  public String getBeginBlockRegexp() {
+    return beginBlockRegexp;
+  }
+
+  public String getEndBlockRegexp() {
+    return endBlockRegexp;
+  }
+}
index 55aac19be3fbc422a204d7ea2c8cf8ad7fea5f07..37d16ef51c52dd3dceb33cb298ee8e9dff842f8e 100644 (file)
  */
 package org.sonar.scanner.issue.ignore.pattern;
 
-import com.google.common.annotations.VisibleForTesting;
 import org.apache.commons.lang.StringUtils;
 import org.sonar.api.config.Settings;
 import org.sonar.core.config.IssueExclusionProperties;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 import static com.google.common.base.Strings.nullToEmpty;
 
 public class IssueExclusionPatternInitializer extends AbstractPatternInitializer {
 
-  private List<IssuePattern> blockPatterns;
-  private List<IssuePattern> allFilePatterns;
-  private PatternMatcher patternMatcher;
+  private List<BlockIssuePattern> blockPatterns;
+  private List<String> allFilePatterns;
 
   public IssueExclusionPatternInitializer(Settings settings) {
     super(settings);
-    patternMatcher = new PatternMatcher();
     loadFileContentPatterns();
   }
 
@@ -46,26 +44,12 @@ public class IssueExclusionPatternInitializer extends AbstractPatternInitializer
     return "sonar.issue.ignore" + ".multicriteria";
   }
 
-  public PatternMatcher getPatternMatcher() {
-    return patternMatcher;
-  }
-
-  @Override
-  public void initializePatternsForPath(String relativePath, String componentKey) {
-    for (IssuePattern pattern : getMulticriteriaPatterns()) {
-      if (pattern.matchResource(relativePath)) {
-        getPatternMatcher().addPatternForComponent(componentKey, pattern);
-      }
-    }
-  }
-
   @Override
   public boolean hasConfiguredPatterns() {
     return hasFileContentPattern() || hasMulticriteriaPatterns();
   }
 
-  @VisibleForTesting
-  protected final void loadFileContentPatterns() {
+  private final void loadFileContentPatterns() {
     // Patterns Block
     blockPatterns = new ArrayList<>();
     String patternConf = StringUtils.defaultIfBlank(getSettings().getString(IssueExclusionProperties.PATTERNS_BLOCK_KEY), "");
@@ -73,11 +57,12 @@ public class IssueExclusionPatternInitializer extends AbstractPatternInitializer
       String propPrefix = IssueExclusionProperties.PATTERNS_BLOCK_KEY + "." + id + ".";
       String beginBlockRegexp = getSettings().getString(propPrefix + IssueExclusionProperties.BEGIN_BLOCK_REGEXP);
       String endBlockRegexp = getSettings().getString(propPrefix + IssueExclusionProperties.END_BLOCK_REGEXP);
-      String[] fields = new String[]{beginBlockRegexp, endBlockRegexp};
+      String[] fields = new String[] {beginBlockRegexp, endBlockRegexp};
       PatternDecoder.checkDoubleRegexpLineConstraints(StringUtils.join(fields, ","), fields);
-      IssuePattern pattern = new IssuePattern().setBeginBlockRegexp(nullToEmpty(beginBlockRegexp)).setEndBlockRegexp(nullToEmpty(endBlockRegexp));
+      BlockIssuePattern pattern = new BlockIssuePattern(nullToEmpty(beginBlockRegexp), nullToEmpty(endBlockRegexp));
       blockPatterns.add(pattern);
     }
+    blockPatterns = Collections.unmodifiableList(blockPatterns);
 
     // Patterns All File
     allFilePatterns = new ArrayList<>();
@@ -86,16 +71,16 @@ public class IssueExclusionPatternInitializer extends AbstractPatternInitializer
       String propPrefix = IssueExclusionProperties.PATTERNS_ALLFILE_KEY + "." + id + ".";
       String allFileRegexp = getSettings().getString(propPrefix + IssueExclusionProperties.FILE_REGEXP);
       PatternDecoder.checkWholeFileRegexp(allFileRegexp);
-      IssuePattern pattern = new IssuePattern().setAllFileRegexp(nullToEmpty(allFileRegexp));
-      allFilePatterns.add(pattern);
+      allFilePatterns.add(nullToEmpty(allFileRegexp));
     }
+    allFilePatterns = Collections.unmodifiableList(allFilePatterns);
   }
 
-  public List<IssuePattern> getBlockPatterns() {
+  public List<BlockIssuePattern> getBlockPatterns() {
     return blockPatterns;
   }
 
-  public List<IssuePattern> getAllFilePatterns() {
+  public List<String> getAllFilePatterns() {
     return allFilePatterns;
   }
 
index c674c45aaff9c159685adec417e54e01107a0b01..7e3992e493c6cc49b657bf7aad817588f735d3c2 100644 (file)
  */
 package org.sonar.scanner.issue.ignore.pattern;
 
-import com.google.common.collect.Maps;
 import org.sonar.api.config.Settings;
 
-import java.util.Map;
-
 public class IssueInclusionPatternInitializer extends AbstractPatternInitializer {
 
-  private Map<String, String> pathForComponent;
-
   public IssueInclusionPatternInitializer(Settings settings) {
     super(settings);
-    pathForComponent = Maps.newHashMap();
   }
 
   @Override
   protected String getMulticriteriaConfigurationKey() {
     return "sonar.issue.enforce" + ".multicriteria";
   }
-
-  @Override
-  public void initializePatternsForPath(String relativePath, String componentKey) {
-    pathForComponent.put(componentKey, relativePath);
-  }
-
-  public String getPathForComponent(String componentKey) {
-    return pathForComponent.get(componentKey);
-  }
 }
index 14867725dcd588f1740ef781b83842cfbab01bee..9ef0d64c9d49b864fa39d8a13bf40764f44bedcd 100644 (file)
 package org.sonar.scanner.issue.ignore.pattern;
 
 import com.google.common.collect.Sets;
+
+import java.util.Collections;
+import java.util.LinkedHashSet;
 import java.util.Set;
 import javax.annotation.Nullable;
 import org.apache.commons.lang.builder.ToStringBuilder;
 import org.apache.commons.lang.builder.ToStringStyle;
 import org.sonar.api.rule.RuleKey;
-import org.sonar.api.scan.issue.filter.FilterableIssue;
 import org.sonar.api.utils.WildcardPattern;
 
 public class IssuePattern {
 
-  private WildcardPattern resourcePattern;
-  private WildcardPattern rulePattern;
-  private Set<Integer> lines = Sets.newLinkedHashSet();
-  private Set<LineRange> lineRanges = Sets.newLinkedHashSet();
-  private String beginBlockRegexp;
-  private String endBlockRegexp;
-  private String allFileRegexp;
-  private boolean checkLines = true;
-
-  public IssuePattern() {
-  }
+  private final WildcardPattern resourcePattern;
+  private final WildcardPattern rulePattern;
+  private final Set<Integer> lines = new LinkedHashSet<>();
+  private final Set<LineRange> lineRanges = new LinkedHashSet<>();
+  private final boolean checkLines;
 
   public IssuePattern(String resourcePattern, String rulePattern) {
-    this.resourcePattern = WildcardPattern.create(resourcePattern);
-    this.rulePattern = WildcardPattern.create(rulePattern);
+    this(resourcePattern, rulePattern, Collections.emptySet());
   }
 
   public IssuePattern(String resourcePattern, String rulePattern, Set<LineRange> lineRanges) {
-    this(resourcePattern, rulePattern);
-    this.lineRanges = lineRanges;
+    this.resourcePattern = WildcardPattern.create(resourcePattern);
+    this.rulePattern = WildcardPattern.create(rulePattern);
+    this.checkLines = !lineRanges.isEmpty();
+    for (LineRange range : lineRanges) {
+      if (range.from() == range.to()) {
+        this.lines.add(range.from());
+      } else {
+        this.lineRanges.add(range);
+      }
+    }
   }
 
   public WildcardPattern getResourcePattern() {
@@ -60,52 +63,10 @@ public class IssuePattern {
     return rulePattern;
   }
 
-  public String getBeginBlockRegexp() {
-    return beginBlockRegexp;
-  }
-
-  public String getEndBlockRegexp() {
-    return endBlockRegexp;
-  }
-
-  public String getAllFileRegexp() {
-    return allFileRegexp;
-  }
-
-  IssuePattern addLineRange(int fromLineId, int toLineId) {
-    lineRanges.add(new LineRange(fromLineId, toLineId));
-    return this;
-  }
-
-  IssuePattern addLine(int lineId) {
-    lines.add(lineId);
-    return this;
-  }
-
   boolean isCheckLines() {
     return checkLines;
   }
 
-  IssuePattern setCheckLines(boolean b) {
-    this.checkLines = b;
-    return this;
-  }
-
-  IssuePattern setBeginBlockRegexp(String beginBlockRegexp) {
-    this.beginBlockRegexp = beginBlockRegexp;
-    return this;
-  }
-
-  IssuePattern setEndBlockRegexp(String endBlockRegexp) {
-    this.endBlockRegexp = endBlockRegexp;
-    return this;
-  }
-
-  IssuePattern setAllFileRegexp(String allFileRegexp) {
-    this.allFileRegexp = allFileRegexp;
-    return this;
-  }
-
   Set<Integer> getAllLines() {
     Set<Integer> allLines = Sets.newLinkedHashSet(lines);
     for (LineRange lineRange : lineRanges) {
@@ -114,18 +75,15 @@ public class IssuePattern {
     return allLines;
   }
 
-  public boolean match(FilterableIssue issue) {
-    boolean match = matchResource(issue.componentKey())
-      && matchRule(issue.ruleKey());
+  public boolean match(@Nullable String componentKey, RuleKey ruleKey, @Nullable Integer line) {
     if (checkLines) {
-      Integer line = issue.line();
       if (line == null) {
-        match = false;
+        return false;
       } else {
-        match = match && matchLine(line);
+        return matchResource(componentKey) && matchRule(ruleKey) && matchLine(line);
       }
     }
-    return match;
+    return matchResource(componentKey) && matchRule(ruleKey);
   }
 
   boolean matchLine(int lineId) {
@@ -147,12 +105,12 @@ public class IssuePattern {
     return rulePattern.match(key);
   }
 
-  boolean matchResource(@Nullable String resource) {
+  public boolean matchResource(@Nullable String resource) {
     return resource != null && resourcePattern.match(resource);
   }
 
   public IssuePattern forResource(String resource) {
-    return new IssuePattern(resource, rulePattern.toString(), lineRanges).setCheckLines(isCheckLines());
+    return new IssuePattern(resource, rulePattern.toString(), lineRanges);
   }
 
   @Override
index 0c76bd5cf2ae933c9f47cc71fbdaba43cb89ded6..b252484fb7a52b41dd0ec0576f010f020fffd9ff 100644 (file)
@@ -28,8 +28,12 @@ public class LineRange {
   private int from;
   private int to;
 
+  public LineRange(int line) {
+    this(line, line);
+  }
+
   public LineRange(int from, int to) {
-    Preconditions.checkArgument(from <= to, "Line range is not valid: %s must be greater than %s", from, to);
+    Preconditions.checkArgument(from <= to, "Line range is not valid: %s must be greater or equal than %s", to, from);
 
     this.from = from;
     this.to = to;
@@ -40,13 +44,21 @@ public class LineRange {
   }
 
   public Set<Integer> toLines() {
-    Set<Integer> lines = new LinkedHashSet<>(to-from+1);
+    Set<Integer> lines = new LinkedHashSet<>(to - from + 1);
     for (int index = from; index <= to; index++) {
       lines.add(index);
     }
     return lines;
   }
 
+  public int from() {
+    return from;
+  }
+
+  public int to() {
+    return to;
+  }
+
   @Override
   public String toString() {
     return "[" + from + "-" + to + "]";
@@ -79,12 +91,6 @@ public class LineRange {
   }
 
   private boolean fieldsDiffer(LineRange other) {
-    if (from != other.from) {
-      return true;
-    }
-    if (to != other.to) {
-      return true;
-    }
-    return false;
+    return from != other.from || to != other.to;
   }
 }
index 32fde5bdd0a975627867cc394caa84306b708bb4..f0ce08b2a19d2e9f4f7a5bf9e965fef0cd7d7d3b 100644 (file)
  */
 package org.sonar.scanner.issue.ignore.pattern;
 
-import com.google.common.annotations.VisibleForTesting;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
 import org.apache.commons.lang.StringUtils;
-import org.sonar.api.utils.SonarException;
 
-import java.util.LinkedList;
-import java.util.List;
+import com.google.common.annotations.VisibleForTesting;
 
 public class PatternDecoder {
-
-  private static final int THREE_FIELDS_PER_LINE = 3;
   private static final String LINE_RANGE_REGEXP = "\\[((\\d+|\\d+-\\d+),?)*\\]";
   private static final String CONFIG_FORMAT_ERROR_PREFIX = "Exclusions > Issues : Invalid format. ";
 
-  public List<IssuePattern> decode(String patternsList) {
-    List<IssuePattern> patterns = new LinkedList<>();
-    String[] patternsLines = StringUtils.split(patternsList, "\n");
-    for (String patternLine : patternsLines) {
-      IssuePattern pattern = decodeLine(patternLine.trim());
-      if (pattern != null) {
-        patterns.add(pattern);
-      }
-    }
-    return patterns;
+  private PatternDecoder() {
+    // static only
   }
-
-  /**
-   * Main method that decodes a line which defines a pattern
-   */
-  public IssuePattern decodeLine(String line) {
-    if (isBlankOrComment(line)) {
-      return null;
-    }
-
-    String[] fields = StringUtils.splitPreserveAllTokens(line, ';');
-    if (fields.length > THREE_FIELDS_PER_LINE) {
-      throw new SonarException(CONFIG_FORMAT_ERROR_PREFIX + "The following line has more than 3 fields separated by comma: " + line);
-    }
-
-    IssuePattern pattern;
-    if (fields.length == THREE_FIELDS_PER_LINE) {
-      checkRegularLineConstraints(line, fields);
-      pattern = new IssuePattern(StringUtils.trim(fields[0]), StringUtils.trim(fields[1]));
-      decodeRangeOfLines(pattern, fields[2]);
-    } else if (fields.length == 2) {
-      checkDoubleRegexpLineConstraints(line, fields);
-      pattern = new IssuePattern().setBeginBlockRegexp(fields[0]).setEndBlockRegexp(fields[1]);
-    } else {
-      checkWholeFileRegexp(fields[0]);
-      pattern = new IssuePattern().setAllFileRegexp(fields[0]);
-    }
-
-    return pattern;
-  }
-
+  
   static void checkRegularLineConstraints(String line, String[] fields) {
     if (!isResource(fields[0])) {
-      throw new SonarException(CONFIG_FORMAT_ERROR_PREFIX + "The first field does not define a resource pattern: " + line);
+      throw new IllegalStateException(CONFIG_FORMAT_ERROR_PREFIX + "The first field does not define a resource pattern: " + line);
     }
     if (!isRule(fields[1])) {
-      throw new SonarException(CONFIG_FORMAT_ERROR_PREFIX + "The second field does not define a rule pattern: " + line);
+      throw new IllegalStateException(CONFIG_FORMAT_ERROR_PREFIX + "The second field does not define a rule pattern: " + line);
     }
     if (!isLinesRange(fields[2])) {
-      throw new SonarException(CONFIG_FORMAT_ERROR_PREFIX + "The third field does not define a range of lines: " + line);
+      throw new IllegalStateException(CONFIG_FORMAT_ERROR_PREFIX + "The third field does not define a range of lines: " + line);
     }
   }
 
   static void checkDoubleRegexpLineConstraints(String line, String[] fields) {
     if (!isRegexp(fields[0])) {
-      throw new SonarException(CONFIG_FORMAT_ERROR_PREFIX + "The first field does not define a regular expression: " + line);
+      throw new IllegalStateException(CONFIG_FORMAT_ERROR_PREFIX + "The first field does not define a regular expression: " + line);
     }
     // As per configuration help, missing second field means: from start regexp to EOF
   }
 
   static void checkWholeFileRegexp(String regexp) {
     if (!isRegexp(regexp)) {
-      throw new SonarException(CONFIG_FORMAT_ERROR_PREFIX + "The field does not define a regular expression: " + regexp);
+      throw new IllegalStateException(CONFIG_FORMAT_ERROR_PREFIX + "The field does not define a regular expression: " + regexp);
     }
   }
 
-  public static void decodeRangeOfLines(IssuePattern pattern, String field) {
+  public static Set<LineRange> decodeRangeOfLines(String field) {
     if (StringUtils.equals(field, "*")) {
-      pattern.setCheckLines(false);
+      return Collections.emptySet();
     } else {
-      pattern.setCheckLines(true);
+      Set<LineRange> lineRanges = new HashSet<>();
+      
       String s = StringUtils.substringBetween(StringUtils.trim(field), "[", "]");
       String[] parts = StringUtils.split(s, ',');
       for (String part : parts) {
         if (StringUtils.contains(part, '-')) {
           String[] range = StringUtils.split(part, '-');
-          pattern.addLineRange(Integer.valueOf(range[0]), Integer.valueOf(range[1]));
+          lineRanges.add(new LineRange(Integer.valueOf(range[0]), Integer.valueOf(range[1])));
         } else {
-          pattern.addLine(Integer.valueOf(part));
+          lineRanges.add(new LineRange(Integer.valueOf(part), Integer.valueOf(part)));
         }
       }
+      return lineRanges;
     }
   }
 
@@ -121,11 +85,6 @@ public class PatternDecoder {
     return StringUtils.equals(field, "*") || java.util.regex.Pattern.matches(LINE_RANGE_REGEXP, field);
   }
 
-  @VisibleForTesting
-  static boolean isBlankOrComment(String line) {
-    return StringUtils.isBlank(line) ^ StringUtils.startsWith(line, "#");
-  }
-
   @VisibleForTesting
   static boolean isResource(String field) {
     return StringUtils.isNotBlank(field);
index 02149148258709c1c76a0e8c8fdc27167c3ba4fe..2d008410cbe4528ed5a156022749a54ac2bdf313 100644 (file)
  */
 package org.sonar.scanner.issue.ignore.pattern;
 
-import org.sonar.api.scan.issue.filter.FilterableIssue;
+import org.sonar.api.rule.RuleKey;
 
+import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.LinkedHashMultimap;
 import com.google.common.collect.Multimap;
 
 import java.util.Collection;
-import java.util.Iterator;
 import java.util.Set;
 
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
 public class PatternMatcher {
 
-  private Multimap<String, IssuePattern> patternByComponent = LinkedHashMultimap.create();
+  private Multimap<String, IssuePattern> excludePatternByComponent = LinkedHashMultimap.create();
 
-  public IssuePattern getMatchingPattern(FilterableIssue issue) {
-    IssuePattern matchingPattern = null;
-    Iterator<IssuePattern> patternIterator = getPatternsForComponent(issue.componentKey()).iterator();
-    while(matchingPattern == null && patternIterator.hasNext()) {
-      IssuePattern nextPattern = patternIterator.next();
-      if (nextPattern.match(issue)) {
-        matchingPattern = nextPattern;
+  @CheckForNull
+  public IssuePattern getMatchingPattern(String componentKey, RuleKey ruleKey, @Nullable Integer line) {
+    for (IssuePattern pattern : getPatternsForComponent(componentKey)) {
+      if (pattern.match(componentKey, ruleKey, line)) {
+        return pattern;
       }
     }
-    return matchingPattern;
+    return null;
   }
 
+  @VisibleForTesting
   public Collection<IssuePattern> getPatternsForComponent(String componentKey) {
-    return patternByComponent.get(componentKey);
+    return excludePatternByComponent.get(componentKey);
   }
 
-  public void addPatternForComponent(String component, IssuePattern pattern) {
-    patternByComponent.put(component, pattern.forResource(component));
+  public void addPatternForComponent(String componentKey, IssuePattern pattern) {
+    excludePatternByComponent.put(componentKey, pattern.forResource(componentKey));
   }
 
-  public void addPatternToExcludeResource(String resource) {
-    addPatternForComponent(resource, new IssuePattern(resource, "*").setCheckLines(false));
+  public void addPatternToExcludeResource(String componentKey) {
+    addPatternForComponent(componentKey, new IssuePattern(componentKey, "*"));
   }
 
-  public void addPatternToExcludeLines(String resource, Set<LineRange> lineRanges) {
-    addPatternForComponent(resource, new IssuePattern(resource, "*", lineRanges).setCheckLines(true));
+  public void addPatternToExcludeLines(String componentKey, Set<LineRange> lineRanges) {
+    addPatternForComponent(componentKey, new IssuePattern(componentKey, "*", lineRanges));
   }
 
 }
index 433e8c5ccbf79839c37afde9dcddb1acf9773e9c..30cdeb0c582471dccf4d8a26e19a8db4a03435c8 100644 (file)
  */
 package org.sonar.scanner.issue.ignore.scanner;
 
-import org.sonar.api.batch.fs.FileSystem;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.CheckForNull;
+
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.batch.fs.internal.FileMetadata.CharHandler;
+import org.sonar.scanner.issue.ignore.pattern.BlockIssuePattern;
 import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer;
-import org.sonar.scanner.issue.ignore.pattern.IssueInclusionPatternInitializer;
+import org.sonar.scanner.issue.ignore.pattern.IssuePattern;
+import org.sonar.scanner.issue.ignore.pattern.PatternMatcher;
 
 public final class IssueExclusionsLoader {
+  private final List<java.util.regex.Pattern> allFilePatterns;
+  private final List<DoubleRegexpMatcher> blockMatchers;
+  private final PatternMatcher patternMatcher;
+  private final IssueExclusionPatternInitializer patternsInitializer;
+  private final boolean enableCharHandler;
+
+  public IssueExclusionsLoader(IssueExclusionPatternInitializer patternsInitializer, PatternMatcher patternMatcher) {
+    this.patternsInitializer = patternsInitializer;
+    this.patternMatcher = patternMatcher;
+    this.allFilePatterns = new ArrayList<>();
+    this.blockMatchers = new ArrayList<>();
 
-  private final IssueExclusionsRegexpScanner regexpScanner;
-  private final IssueExclusionPatternInitializer exclusionPatternInitializer;
-  private final IssueInclusionPatternInitializer inclusionPatternInitializer;
-  private final FileSystem fileSystem;
-
-  public IssueExclusionsLoader(IssueExclusionsRegexpScanner regexpScanner, IssueExclusionPatternInitializer exclusionPatternInitializer,
-    IssueInclusionPatternInitializer inclusionPatternInitializer, FileSystem fileSystem) {
-    this.regexpScanner = regexpScanner;
-    this.exclusionPatternInitializer = exclusionPatternInitializer;
-    this.inclusionPatternInitializer = inclusionPatternInitializer;
-    this.fileSystem = fileSystem;
+    for (String pattern : patternsInitializer.getAllFilePatterns()) {
+      allFilePatterns.add(java.util.regex.Pattern.compile(pattern));
+    }
+    for (BlockIssuePattern pattern : patternsInitializer.getBlockPatterns()) {
+      blockMatchers.add(new DoubleRegexpMatcher(
+        java.util.regex.Pattern.compile(pattern.getBeginBlockRegexp()),
+        java.util.regex.Pattern.compile(pattern.getEndBlockRegexp())));
+    }
+    enableCharHandler = !allFilePatterns.isEmpty() || !blockMatchers.isEmpty();
   }
 
   public boolean shouldExecute() {
-    return inclusionPatternInitializer.hasConfiguredPatterns()
-      || exclusionPatternInitializer.hasConfiguredPatterns();
+    return patternsInitializer.hasMulticriteriaPatterns();
   }
 
-  public void preLoadAllFiles() {
-    for (InputFile inputFile : fileSystem.inputFiles(fileSystem.predicates().all())) {
-      loadFile(inputFile);
+  public void addMulticriteriaPatterns(String relativePath, String componentKey) {
+    for (IssuePattern pattern : patternsInitializer.getMulticriteriaPatterns()) {
+      if (pattern.matchResource(relativePath)) {
+        patternMatcher.addPatternForComponent(componentKey, pattern);
+      }
     }
   }
 
-  public boolean isLoaded(InputFile inputFile) {
-    String componentEffectiveKey = ((DefaultInputFile) inputFile).key();
-    return inclusionPatternInitializer.getPathForComponent(componentEffectiveKey) != null;
+  @CheckForNull
+  public CharHandler createCharHandlerFor(String componentKey) {
+    if (enableCharHandler) {
+      return new IssueExclusionsRegexpScanner(componentKey, allFilePatterns, blockMatchers, patternMatcher);
+    }
+    return null;
   }
 
-  public void loadFile(InputFile inputFile) {
-    try {
-      String componentEffectiveKey = ((DefaultInputFile) inputFile).key();
-      String path = inputFile.relativePath();
-      inclusionPatternInitializer.initializePatternsForPath(path, componentEffectiveKey);
-      exclusionPatternInitializer.initializePatternsForPath(path, componentEffectiveKey);
-      if (exclusionPatternInitializer.hasFileContentPattern()) {
-        regexpScanner.scan(componentEffectiveKey, inputFile.path(), inputFile.charset());
-      }
-    } catch (Exception e) {
-      throw new IllegalStateException("Unable to read the source file : '" + inputFile.absolutePath() + "' with the charset : '"
-        + inputFile.charset().name() + "'.", e);
+  public static class DoubleRegexpMatcher {
+
+    private java.util.regex.Pattern firstPattern;
+    private java.util.regex.Pattern secondPattern;
+
+    DoubleRegexpMatcher(java.util.regex.Pattern firstPattern, java.util.regex.Pattern secondPattern) {
+      this.firstPattern = firstPattern;
+      this.secondPattern = secondPattern;
+    }
+
+    boolean matchesFirstPattern(String line) {
+      return firstPattern.matcher(line).find();
+    }
+
+    boolean matchesSecondPattern(String line) {
+      return hasSecondPattern() && secondPattern.matcher(line).find();
+    }
+
+    boolean hasSecondPattern() {
+      return StringUtils.isNotEmpty(secondPattern.toString());
     }
   }
 
@@ -75,5 +102,4 @@ public final class IssueExclusionsLoader {
   public String toString() {
     return "Issues Exclusions - Source Scanner";
   }
-
 }
index 0c4794cb2b9b95ac77a2973115f76c21b6659580..0ad4373665a4a0141665bdb634b6bb668c4f8eac 100644 (file)
  */
 package org.sonar.scanner.issue.ignore.scanner;
 
-import org.apache.commons.lang.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.batch.ScannerSide;
-import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer;
-import org.sonar.scanner.issue.ignore.pattern.IssuePattern;
-import org.sonar.scanner.issue.ignore.pattern.LineRange;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.nio.charset.Charset;
-import java.nio.file.Files;
-import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.regex.Pattern;
 
-@ScannerSide
-public class IssueExclusionsRegexpScanner {
-
-  private static final Logger LOG = LoggerFactory.getLogger(IssueExclusionsRegexpScanner.class);
-
-  private IssueExclusionPatternInitializer exclusionPatternInitializer;
-  private List<java.util.regex.Pattern> allFilePatterns;
-  private List<DoubleRegexpMatcher> blockMatchers;
-
-  // fields to be reset at every new scan
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.batch.fs.internal.FileMetadata.CharHandler;
+import org.sonar.scanner.issue.ignore.pattern.LineRange;
+import org.sonar.scanner.issue.ignore.pattern.PatternMatcher;
+import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader.DoubleRegexpMatcher;
+
+public class IssueExclusionsRegexpScanner extends CharHandler {
+  private static final Logger LOG = LoggerFactory.getLogger(IssueExclusionsLoader.class);
+
+  private final StringBuilder sb = new StringBuilder();
+  private final List<Pattern> allFilePatterns;
+  private final List<DoubleRegexpMatcher> blockMatchers;
+  private final String componentKey;
+  private final PatternMatcher patternMatcher;
+
+  private int lineIndex = 1;
+  private List<LineExclusion> lineExclusions = new ArrayList<>();
+  private LineExclusion currentLineExclusion = null;
+  private int fileLength = 0;
   private DoubleRegexpMatcher currentMatcher;
-  private int fileLength;
-  private List<LineExclusion> lineExclusions;
-  private LineExclusion currentLineExclusion;
 
-  public IssueExclusionsRegexpScanner(IssueExclusionPatternInitializer patternsInitializer) {
-    this.exclusionPatternInitializer = patternsInitializer;
-
-    lineExclusions = new ArrayList<>();
-    allFilePatterns = new ArrayList<>();
-    blockMatchers = new ArrayList<>();
-
-    for (IssuePattern pattern : patternsInitializer.getAllFilePatterns()) {
-      allFilePatterns.add(java.util.regex.Pattern.compile(pattern.getAllFileRegexp()));
-    }
-    for (IssuePattern pattern : patternsInitializer.getBlockPatterns()) {
-      blockMatchers.add(new DoubleRegexpMatcher(
-        java.util.regex.Pattern.compile(pattern.getBeginBlockRegexp()),
-        java.util.regex.Pattern.compile(pattern.getEndBlockRegexp())));
-    }
-
-    init();
+  IssueExclusionsRegexpScanner(String componentKey, List<Pattern> allFilePatterns, List<DoubleRegexpMatcher> blockMatchers, PatternMatcher patternMatcher) {
+    this.allFilePatterns = allFilePatterns;
+    this.blockMatchers = blockMatchers;
+    this.patternMatcher = patternMatcher;
+    this.componentKey = componentKey;
+    String relativePath = StringUtils.substringAfterLast(componentKey, ":");
+    LOG.info("'{}' generating issue exclusions", relativePath);
   }
 
-  private void init() {
-    currentMatcher = null;
-    fileLength = 0;
-    lineExclusions.clear();
-    currentLineExclusion = null;
+  @Override
+  protected void handleIgnoreEoL(char c) {
+    sb.append(c);
   }
 
-  public void scan(String resource, Path filePath, Charset encoding) throws IOException {
-    LOG.debug("Scanning {}", resource);
-    init();
-
-    int lineIndex = 0;
-    try (BufferedReader br = Files.newBufferedReader(filePath, encoding)) {
-      String line;
-      while ((line = br.readLine()) != null) {
-        lineIndex++;
-        if (line.trim().length() == 0) {
-          continue;
-        }
+  @Override
+  protected void newLine() {
+    processLine(sb.toString());
+    sb.setLength(0);
+    lineIndex++;
+  }
 
-        // first check the single regexp patterns that can be used to totally exclude a file
-        for (java.util.regex.Pattern pattern : allFilePatterns) {
-          if (pattern.matcher(line).find()) {
-            exclusionPatternInitializer.getPatternMatcher().addPatternToExcludeResource(resource);
-            // nothing more to do on this file
-            LOG.debug("- Exclusion pattern '{}': every issue in this file will be ignored.", pattern);
-            return;
-          }
-        }
-
-        // then check the double regexps if we're still here
-        checkDoubleRegexps(line, lineIndex);
-      }
-    }
+  @Override
+  protected void eof() {
+    processLine(sb.toString());
 
     if (currentMatcher != null && !currentMatcher.hasSecondPattern()) {
       // this will happen when there is a start block regexp but no end block regexp
@@ -116,14 +83,33 @@ public class IssueExclusionsRegexpScanner {
     if (!lineExclusions.isEmpty()) {
       Set<LineRange> lineRanges = convertLineExclusionsToLineRanges();
       LOG.debug("- Line exclusions found: {}", lineRanges);
-      exclusionPatternInitializer.getPatternMatcher().addPatternToExcludeLines(resource, lineRanges);
+      patternMatcher.addPatternToExcludeLines(componentKey, lineRanges);
     }
   }
 
+  private void processLine(String line) {
+    if (line.trim().length() == 0) {
+      return;
+    }
+
+    // first check the single regexp patterns that can be used to totally exclude a file
+    for (Pattern pattern : allFilePatterns) {
+      if (pattern.matcher(line).find()) {
+        patternMatcher.addPatternToExcludeResource(componentKey);
+        // nothing more to do on this file
+        LOG.debug("- Exclusion pattern '{}': every issue in this file will be ignored.", pattern);
+        return;
+      }
+    }
+
+    // then check the double regexps if we're still here
+    checkDoubleRegexps(line, lineIndex);
+  }
+
   private Set<LineRange> convertLineExclusionsToLineRanges() {
     Set<LineRange> lineRanges = new HashSet<>(lineExclusions.size());
     for (LineExclusion lineExclusion : lineExclusions) {
-      lineRanges.add(lineExclusion.toLineRange());
+      lineRanges.add(lineExclusion.toLineRange(fileLength));
     }
     return lineRanges;
   }
@@ -155,8 +141,7 @@ public class IssueExclusionsRegexpScanner {
     currentLineExclusion = null;
   }
 
-  private class LineExclusion {
-
+  private static class LineExclusion {
     private int start;
     private int end;
 
@@ -169,33 +154,8 @@ public class IssueExclusionsRegexpScanner {
       this.end = end;
     }
 
-    public LineRange toLineRange() {
+    public LineRange toLineRange(int fileLength) {
       return new LineRange(start, end == -1 ? fileLength : end);
     }
-
-  }
-
-  private static class DoubleRegexpMatcher {
-
-    private java.util.regex.Pattern firstPattern;
-    private java.util.regex.Pattern secondPattern;
-
-    DoubleRegexpMatcher(java.util.regex.Pattern firstPattern, java.util.regex.Pattern secondPattern) {
-      this.firstPattern = firstPattern;
-      this.secondPattern = secondPattern;
-    }
-
-    boolean matchesFirstPattern(String line) {
-      return firstPattern.matcher(line).find();
-    }
-
-    boolean matchesSecondPattern(String line) {
-      return hasSecondPattern() && secondPattern.matcher(line).find();
-    }
-
-    boolean hasSecondPattern() {
-      return StringUtils.isNotEmpty(secondPattern.toString());
-    }
   }
-
 }
index e48247aee051c4c0cc369899cf0890cf475dd1d0..46acfff0279b1c1f1b81f6fe7f4e43293b5920c4 100644 (file)
 package org.sonar.scanner.phases;
 
 import org.sonar.api.batch.SensorContext;
+import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.batch.fs.internal.DefaultInputModule;
-import org.sonar.api.config.Settings;
 import org.sonar.scanner.events.BatchStepEvent;
 import org.sonar.scanner.events.EventBus;
 import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
 import org.sonar.scanner.rule.QProfileVerifier;
 import org.sonar.scanner.scan.filesystem.DefaultModuleFileSystem;
 import org.sonar.scanner.scan.filesystem.FileSystemLogger;
-import org.sonar.scanner.scan.filesystem.InputFileBuilder;
 
 public abstract class AbstractPhaseExecutor {
 
@@ -41,11 +40,10 @@ public abstract class AbstractPhaseExecutor {
   private final DefaultModuleFileSystem fs;
   private final QProfileVerifier profileVerifier;
   private final IssueExclusionsLoader issueExclusionsLoader;
-  private final boolean preloadIssueExclusions;
 
   public AbstractPhaseExecutor(InitializersExecutor initializersExecutor, PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor,
     SensorContext sensorContext, EventBus eventBus, FileSystemLogger fsLogger, DefaultModuleFileSystem fs, QProfileVerifier profileVerifier,
-    IssueExclusionsLoader issueExclusionsLoader, Settings settings) {
+    IssueExclusionsLoader issueExclusionsLoader) {
     this.postJobsExecutor = postJobsExecutor;
     this.initializersExecutor = initializersExecutor;
     this.sensorsExecutor = sensorsExecutor;
@@ -55,7 +53,6 @@ public abstract class AbstractPhaseExecutor {
     this.fs = fs;
     this.profileVerifier = profileVerifier;
     this.issueExclusionsLoader = issueExclusionsLoader;
-    this.preloadIssueExclusions = settings.getBoolean(InputFileBuilder.PRELOAD_FILE_METADATA_KEY);
   }
 
   /**
@@ -92,10 +89,14 @@ public abstract class AbstractPhaseExecutor {
   protected abstract void executeOnRoot();
 
   private void initIssueExclusions() {
-    if (preloadIssueExclusions && issueExclusionsLoader.shouldExecute()) {
+    if (issueExclusionsLoader.shouldExecute()) {
       String stepName = "Init issue exclusions";
       eventBus.fireEvent(new BatchStepEvent(stepName, true));
-      issueExclusionsLoader.preLoadAllFiles();
+
+      for (InputFile inputFile : fs.inputFiles(fs.predicates().all())) {
+        issueExclusionsLoader.addMulticriteriaPatterns(inputFile.relativePath(), inputFile.key());
+      }
+
       eventBus.fireEvent(new BatchStepEvent(stepName, false));
     }
   }
index b650656b59239fdc7df6048b82a3942a096836cc..7893e6a0024e9be72367418c9951be2830253ce3 100644 (file)
@@ -22,7 +22,6 @@ package org.sonar.scanner.phases;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.sonar.api.batch.SensorContext;
-import org.sonar.api.config.Settings;
 import org.sonar.scanner.events.BatchStepEvent;
 import org.sonar.scanner.events.EventBus;
 import org.sonar.scanner.issue.IssueCallback;
@@ -44,8 +43,8 @@ public final class IssuesPhaseExecutor extends AbstractPhaseExecutor {
 
   public IssuesPhaseExecutor(InitializersExecutor initializersExecutor, PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor, SensorContext sensorContext,
     EventBus eventBus, FileSystemLogger fsLogger, IssuesReports jsonReport, DefaultModuleFileSystem fs, QProfileVerifier profileVerifier,
-    IssueExclusionsLoader issueExclusionsLoader, IssueTransition localIssueTracking, IssueCallback issueCallback, Settings settings) {
-    super(initializersExecutor, postJobsExecutor, sensorsExecutor, sensorContext, eventBus, fsLogger, fs, profileVerifier, issueExclusionsLoader, settings);
+    IssueExclusionsLoader issueExclusionsLoader, IssueTransition localIssueTracking, IssueCallback issueCallback) {
+    super(initializersExecutor, postJobsExecutor, sensorsExecutor, sensorContext, eventBus, fsLogger, fs, profileVerifier, issueExclusionsLoader);
     this.eventBus = eventBus;
     this.issuesReport = jsonReport;
     this.localIssueTracking = localIssueTracking;
index e8bf655674d3cb15057a546f52f237ad63544ff3..434c88a96ddb7a48ca328479d8d3dcaa1114a7b2 100644 (file)
@@ -20,7 +20,6 @@
 package org.sonar.scanner.phases;
 
 import org.sonar.api.batch.SensorContext;
-import org.sonar.api.config.Settings;
 import org.sonar.scanner.cpd.CpdExecutor;
 import org.sonar.scanner.events.BatchStepEvent;
 import org.sonar.scanner.events.EventBus;
@@ -39,9 +38,9 @@ public final class PublishPhaseExecutor extends AbstractPhaseExecutor {
   private final ScmPublisher scm;
 
   public PublishPhaseExecutor(InitializersExecutor initializersExecutor, PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor, SensorContext sensorContext,
-    EventBus eventBus, ReportPublisher reportPublisher, FileSystemLogger fsLogger, DefaultModuleFileSystem fs, Settings settings,
+    EventBus eventBus, ReportPublisher reportPublisher, FileSystemLogger fsLogger, DefaultModuleFileSystem fs,
     QProfileVerifier profileVerifier, IssueExclusionsLoader issueExclusionsLoader, CpdExecutor cpdExecutor, ScmPublisher scm) {
-    super(initializersExecutor, postJobsExecutor, sensorsExecutor, sensorContext, eventBus, fsLogger, fs, profileVerifier, issueExclusionsLoader, settings);
+    super(initializersExecutor, postJobsExecutor, sensorsExecutor, sensorContext, eventBus, fsLogger, fs, profileVerifier, issueExclusionsLoader);
     this.eventBus = eventBus;
     this.reportPublisher = reportPublisher;
     this.cpdExecutor = cpdExecutor;
index 9053ad07f89aea2294ff060a4289ecbb84bdbc54..b7ba4b5cf0bbfc0d6e6e6eb666f02b6112ec9fc6 100644 (file)
@@ -44,8 +44,8 @@ import org.sonar.scanner.issue.ignore.EnforceIssuesFilter;
 import org.sonar.scanner.issue.ignore.IgnoreIssuesFilter;
 import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer;
 import org.sonar.scanner.issue.ignore.pattern.IssueInclusionPatternInitializer;
+import org.sonar.scanner.issue.ignore.pattern.PatternMatcher;
 import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
-import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsRegexpScanner;
 import org.sonar.scanner.phases.AbstractPhaseExecutor;
 import org.sonar.scanner.phases.InitializersExecutor;
 import org.sonar.scanner.phases.IssuesPhaseExecutor;
@@ -152,7 +152,7 @@ public class ModuleScanContainer extends ComponentContainer {
       // issue exclusions
       IssueInclusionPatternInitializer.class,
       IssueExclusionPatternInitializer.class,
-      IssueExclusionsRegexpScanner.class,
+      PatternMatcher.class,
       IssueExclusionsLoader.class,
       EnforceIssuesFilter.class,
       IgnoreIssuesFilter.class,
index 5e814625b5271364e9977385a32847f9aa849db0..c04483cc784ff4f433a6529ed2562f9e134fffa9 100644 (file)
@@ -35,6 +35,7 @@ import org.sonar.api.batch.fs.internal.DefaultInputFile;
 import org.sonar.api.batch.fs.internal.DefaultInputModule;
 import org.sonar.api.batch.fs.internal.FileMetadata;
 import org.sonar.api.batch.fs.internal.Metadata;
+import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
 
 class MetadataGenerator {
   private static final Logger LOG = LoggerFactory.getLogger(MetadataGenerator.class);
@@ -47,11 +48,13 @@ class MetadataGenerator {
   private final StatusDetection statusDetection;
   private final FileMetadata fileMetadata;
   private final DefaultInputModule inputModule;
+  private final IssueExclusionsLoader exclusionsScanner;
 
-  MetadataGenerator(DefaultInputModule inputModule, StatusDetection statusDetection, FileMetadata fileMetadata) {
+  MetadataGenerator(DefaultInputModule inputModule, StatusDetection statusDetection, FileMetadata fileMetadata, IssueExclusionsLoader exclusionsScanner) {
     this.inputModule = inputModule;
     this.statusDetection = statusDetection;
     this.fileMetadata = fileMetadata;
+    this.exclusionsScanner = exclusionsScanner;
   }
 
   /**
@@ -62,11 +65,10 @@ class MetadataGenerator {
     try {
       Charset charset = detectCharset(inputFile.path(), defaultEncoding);
       inputFile.setCharset(charset);
-      Metadata metadata = fileMetadata.readMetadata(inputFile.file(), charset);
+      Metadata metadata = fileMetadata.readMetadata(inputFile.file(), charset, exclusionsScanner.createCharHandlerFor(inputFile.key()));
       inputFile.setMetadata(metadata);
       inputFile.setStatus(statusDetection.status(inputModule.definition().getKeyWithBranch(), inputFile.relativePath(), metadata.hash()));
-      LOG.debug("'{}' generated metadata {} with charset '{}'",
-        inputFile.relativePath(), inputFile.type() == Type.TEST ? "as test " : "", charset);
+      LOG.debug("'{}' generated metadata {} with charset '{}'", inputFile.relativePath(), inputFile.type() == Type.TEST ? "as test " : "", charset);
     } catch (Exception e) {
       throw new IllegalStateException(e);
     }
index 59d89e38539d7cf8f84fefe9cbcfad738a7e5cdf..4e935f1905eb17a838febd1b6ad93560be8ee336 100644 (file)
@@ -23,10 +23,12 @@ import org.picocontainer.injectors.ProviderAdapter;
 import org.sonar.api.batch.ScannerSide;
 import org.sonar.api.batch.fs.internal.DefaultInputModule;
 import org.sonar.api.batch.fs.internal.FileMetadata;
+import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
 
 @ScannerSide
 public class MetadataGeneratorProvider extends ProviderAdapter {
-  public MetadataGenerator provide(DefaultInputModule inputModule, StatusDetectionFactory statusDetectionFactory, FileMetadata fileMetadata) {
-    return new MetadataGenerator(inputModule, statusDetectionFactory.create(), fileMetadata);
+  public MetadataGenerator provide(DefaultInputModule inputModule, StatusDetectionFactory statusDetectionFactory, FileMetadata fileMetadata,
+    IssueExclusionsLoader exclusionsScanner) {
+    return new MetadataGenerator(inputModule, statusDetectionFactory.create(), fileMetadata, exclusionsScanner);
   }
 }
index af240c4766015030b69840887cfeec104dce42b2..c180e8e1da60b84d86f25d58080872549aeecb8d 100644 (file)
@@ -24,7 +24,6 @@ import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.runners.MockitoJUnitRunner;
-import org.sonar.api.batch.fs.FileSystem;
 import org.sonar.api.batch.fs.internal.DefaultInputFile;
 import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
 import org.sonar.api.batch.rule.internal.ActiveRulesBuilder;
@@ -36,10 +35,6 @@ import org.sonar.api.rule.Severity;
 import org.sonar.api.utils.MessageException;
 import org.sonar.scanner.issue.IssueFilters;
 import org.sonar.scanner.issue.ModuleIssues;
-import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer;
-import org.sonar.scanner.issue.ignore.pattern.IssueInclusionPatternInitializer;
-import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
-import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsRegexpScanner;
 import org.sonar.scanner.protocol.output.ScannerReport;
 import org.sonar.scanner.report.ReportPublisher;
 
@@ -211,9 +206,7 @@ public class ModuleIssuesTest {
    * Every rules and active rules has to be added in builders before creating ModuleIssues
    */
   private void initModuleIssues() {
-    IssueExclusionsLoader issueExclusionsLoader = new IssueExclusionsLoader(mock(IssueExclusionsRegexpScanner.class), mock(IssueExclusionPatternInitializer.class),
-      mock(IssueInclusionPatternInitializer.class), mock(FileSystem.class));
-    moduleIssues = new ModuleIssues(activeRulesBuilder.build(), ruleBuilder.build(), filters, reportPublisher, issueExclusionsLoader);
+    moduleIssues = new ModuleIssues(activeRulesBuilder.build(), ruleBuilder.build(), filters, reportPublisher);
   }
 
 }
index dab1de1df03b6430875e78d7508737c5ca927e07..d3089b298fa56e4966aab2ec13ad1237b81efe3d 100644 (file)
@@ -25,11 +25,14 @@ import com.google.common.collect.ImmutableList;
 import org.junit.Before;
 import org.junit.Test;
 import org.sonar.api.scan.issue.filter.IssueFilterChain;
+import org.sonar.api.batch.fs.InputComponent;
+import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.utils.WildcardPattern;
 import org.sonar.scanner.issue.ignore.EnforceIssuesFilter;
 import org.sonar.scanner.issue.ignore.pattern.IssueInclusionPatternInitializer;
 import org.sonar.scanner.issue.ignore.pattern.IssuePattern;
+import org.sonar.scanner.scan.filesystem.InputComponentStore;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
@@ -40,18 +43,20 @@ import static org.mockito.Mockito.when;
 public class EnforceIssuesFilterTest {
 
   private IssueInclusionPatternInitializer exclusionPatternInitializer;
+  private InputComponentStore inputComponentStore;
   private EnforceIssuesFilter ignoreFilter;
   private FilterableIssue issue;
   private IssueFilterChain chain;
 
   @Before
   public void init() {
+    inputComponentStore = mock(InputComponentStore.class);
     exclusionPatternInitializer = mock(IssueInclusionPatternInitializer.class);
     issue = mock(FilterableIssue.class);
     chain = mock(IssueFilterChain.class);
     when(chain.accept(issue)).thenReturn(true);
 
-    ignoreFilter = new EnforceIssuesFilter(exclusionPatternInitializer);
+    ignoreFilter = new EnforceIssuesFilter(exclusionPatternInitializer, inputComponentStore);
   }
 
   @Test
@@ -95,12 +100,16 @@ public class EnforceIssuesFilterTest {
     when(matching.getResourcePattern()).thenReturn(pathPattern);
     when(pathPattern.match(path)).thenReturn(true);
     when(exclusionPatternInitializer.getMulticriteriaPatterns()).thenReturn(ImmutableList.of(matching));
-    when(exclusionPatternInitializer.getPathForComponent(componentKey)).thenReturn(path);
+    when(inputComponentStore.getByKey(componentKey)).thenReturn(createComponentWithPath(path));
 
     assertThat(ignoreFilter.accept(issue, chain)).isTrue();
     verifyZeroInteractions(chain);
   }
 
+  private InputComponent createComponentWithPath(String path) {
+    return new TestInputFileBuilder("", path).build();
+  }
+
   @Test
   public void shouldRefuseIssueIfRuleMatchesButNotPath() {
     String rule = "rule";
@@ -119,7 +128,7 @@ public class EnforceIssuesFilterTest {
     when(matching.getResourcePattern()).thenReturn(pathPattern);
     when(pathPattern.match(path)).thenReturn(false);
     when(exclusionPatternInitializer.getMulticriteriaPatterns()).thenReturn(ImmutableList.of(matching));
-    when(exclusionPatternInitializer.getPathForComponent(componentKey)).thenReturn(path);
+    when(inputComponentStore.getByKey(componentKey)).thenReturn(createComponentWithPath(path));
 
     assertThat(ignoreFilter.accept(issue, chain)).isFalse();
     verifyZeroInteractions(chain);
@@ -143,7 +152,7 @@ public class EnforceIssuesFilterTest {
     when(matching.getResourcePattern()).thenReturn(pathPattern);
     when(pathPattern.match(path)).thenReturn(false);
     when(exclusionPatternInitializer.getMulticriteriaPatterns()).thenReturn(ImmutableList.of(matching));
-    when(exclusionPatternInitializer.getPathForComponent(componentKey)).thenReturn(null);
+    when(inputComponentStore.getByKey(componentKey)).thenReturn(null);
 
     assertThat(ignoreFilter.accept(issue, chain)).isFalse();
     verifyZeroInteractions(chain);
index b1a88ce858cc6e989d9a205dd4e9158c00127e69..ccf1ed016c6de63d0597e3c247c72f368ae19d47 100644 (file)
  */
 package org.sonar.scanner.issue.ignore;
 
+import org.sonar.api.rule.RuleKey;
 import org.sonar.api.scan.issue.filter.FilterableIssue;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.sonar.api.scan.issue.filter.IssueFilterChain;
 import org.sonar.scanner.issue.ignore.IgnoreIssuesFilter;
-import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer;
 import org.sonar.scanner.issue.ignore.pattern.IssuePattern;
 import org.sonar.scanner.issue.ignore.pattern.PatternMatcher;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.when;
 
 public class IgnoreIssuesFilterTest {
 
-  private IssueExclusionPatternInitializer exclusionPatternInitializer;
   private PatternMatcher exclusionPatternMatcher;
   private IgnoreIssuesFilter ignoreFilter;
   private FilterableIssue issue;
@@ -44,25 +45,23 @@ public class IgnoreIssuesFilterTest {
   @Before
   public void init() {
     exclusionPatternMatcher = mock(PatternMatcher.class);
-    exclusionPatternInitializer = mock(IssueExclusionPatternInitializer.class);
-    when(exclusionPatternInitializer.getPatternMatcher()).thenReturn(exclusionPatternMatcher);
     issue = mock(FilterableIssue.class);
     chain = mock(IssueFilterChain.class);
     when(chain.accept(issue)).thenReturn(true);
 
-    ignoreFilter = new IgnoreIssuesFilter(exclusionPatternInitializer);
+    ignoreFilter = new IgnoreIssuesFilter(exclusionPatternMatcher);
   }
 
   @Test
   public void shouldPassToChainIfMatcherHasNoPatternForIssue() {
-    when(exclusionPatternMatcher.getMatchingPattern(issue)).thenReturn(null);
+    when(exclusionPatternMatcher.getMatchingPattern(anyString(), any(RuleKey.class), any(Integer.class))).thenReturn(null);
 
     assertThat(ignoreFilter.accept(issue, chain)).isTrue();
   }
 
   @Test
   public void shouldAcceptOrRefuseIfMatcherHasPatternForIssue() {
-    when(exclusionPatternMatcher.getMatchingPattern(issue)).thenReturn(mock(IssuePattern.class));
+    when(exclusionPatternMatcher.getMatchingPattern(anyString(), any(RuleKey.class), any(Integer.class))).thenReturn(mock(IssuePattern.class));
 
     assertThat(ignoreFilter.accept(issue, chain)).isFalse();
   }
index a298c822a2eb15d135eddfe52a1a9c4af48a0f2e..7fadd593235e7aa23d017e9ae5592ae403fc8717 100644 (file)
  */
 package org.sonar.scanner.issue.ignore.pattern;
 
-
 import org.junit.Before;
 import org.junit.Test;
 import org.sonar.api.config.PropertyDefinitions;
 import org.sonar.api.config.Settings;
 import org.sonar.api.config.MapSettings;
-import org.sonar.api.utils.SonarException;
 import org.sonar.core.config.IssueExclusionProperties;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class IssueExclusionPatternInitializerTest {
-
   private IssueExclusionPatternInitializer patternsInitializer;
-
   private Settings settings;
 
   @Before
   public void init() {
     settings = new MapSettings(new PropertyDefinitions(IssueExclusionProperties.all()));
-    patternsInitializer = new IssueExclusionPatternInitializer(settings);
   }
 
   @Test
   public void testNoConfiguration() {
-    patternsInitializer.initPatterns();
+    patternsInitializer = new IssueExclusionPatternInitializer(settings);
     assertThat(patternsInitializer.hasConfiguredPatterns()).isFalse();
     assertThat(patternsInitializer.getMulticriteriaPatterns().size()).isEqualTo(0);
   }
 
-  @Test
-  public void shouldHavePatternsBasedOnMulticriteriaPattern() {
-    settings.setProperty("sonar.issue.ignore" + ".multicriteria", "1,2");
-    settings.setProperty("sonar.issue.ignore" + ".multicriteria" + ".1." + "resourceKey", "org/foo/Bar.java");
-    settings.setProperty("sonar.issue.ignore" + ".multicriteria" + ".1." + "ruleKey", "*");
-    settings.setProperty("sonar.issue.ignore" + ".multicriteria" + ".2." + "resourceKey", "org/foo/Hello.java");
-    settings.setProperty("sonar.issue.ignore" + ".multicriteria" + ".2." + "ruleKey", "checkstyle:MagicNumber");
-    patternsInitializer.initPatterns();
-
-    assertThat(patternsInitializer.hasConfiguredPatterns()).isTrue();
-    assertThat(patternsInitializer.hasFileContentPattern()).isFalse();
-    assertThat(patternsInitializer.hasMulticriteriaPatterns()).isTrue();
-    assertThat(patternsInitializer.getMulticriteriaPatterns().size()).isEqualTo(2);
-    assertThat(patternsInitializer.getBlockPatterns().size()).isEqualTo(0);
-    assertThat(patternsInitializer.getAllFilePatterns().size()).isEqualTo(0);
-
-    patternsInitializer.initializePatternsForPath("org/foo/Bar.java", "org.foo.Bar");
-    patternsInitializer.initializePatternsForPath("org/foo/Baz.java", "org.foo.Baz");
-    patternsInitializer.initializePatternsForPath("org/foo/Hello.java", "org.foo.Hello");
-
-    assertThat(patternsInitializer.getPatternMatcher().getPatternsForComponent("org.foo.Bar")).hasSize(1);
-    assertThat(patternsInitializer.getPatternMatcher().getPatternsForComponent("org.foo.Baz")).hasSize(0);
-    assertThat(patternsInitializer.getPatternMatcher().getPatternsForComponent("org.foo.Hello")).hasSize(1);
-
-  }
-
-  @Test(expected = SonarException.class)
+  @Test(expected = IllegalStateException.class)
   public void shouldLogInvalidResourceKey() {
     settings.setProperty("sonar.issue.ignore" + ".multicriteria", "1");
     settings.setProperty("sonar.issue.ignore" + ".multicriteria" + ".1." + "resourceKey", "");
     settings.setProperty("sonar.issue.ignore" + ".multicriteria" + ".1." + "ruleKey", "*");
-    patternsInitializer.initPatterns();
+    patternsInitializer = new IssueExclusionPatternInitializer(settings);
   }
 
-  @Test(expected = SonarException.class)
+  @Test(expected = IllegalStateException.class)
   public void shouldLogInvalidRuleKey() {
     settings.setProperty("sonar.issue.ignore" + ".multicriteria", "1");
     settings.setProperty("sonar.issue.ignore" + ".multicriteria" + ".1." + "resourceKey", "*");
     settings.setProperty("sonar.issue.ignore" + ".multicriteria" + ".1." + "ruleKey", "");
-    patternsInitializer.initPatterns();
+    patternsInitializer = new IssueExclusionPatternInitializer(settings);
   }
 
   @Test
@@ -100,7 +69,7 @@ public class IssueExclusionPatternInitializerTest {
     settings.setProperty(IssueExclusionProperties.PATTERNS_BLOCK_KEY + ".2." + IssueExclusionProperties.END_BLOCK_REGEXP, "// FOO-ON");
     settings.setProperty(IssueExclusionProperties.PATTERNS_BLOCK_KEY + ".3." + IssueExclusionProperties.BEGIN_BLOCK_REGEXP, "// IGNORE-TO-EOF");
     settings.setProperty(IssueExclusionProperties.PATTERNS_BLOCK_KEY + ".3." + IssueExclusionProperties.END_BLOCK_REGEXP, "");
-    patternsInitializer.loadFileContentPatterns();
+    patternsInitializer = new IssueExclusionPatternInitializer(settings);
 
     assertThat(patternsInitializer.hasConfiguredPatterns()).isTrue();
     assertThat(patternsInitializer.hasFileContentPattern()).isTrue();
@@ -110,12 +79,12 @@ public class IssueExclusionPatternInitializerTest {
     assertThat(patternsInitializer.getAllFilePatterns().size()).isEqualTo(0);
   }
 
-  @Test(expected = SonarException.class)
+  @Test(expected = IllegalStateException.class)
   public void shouldLogInvalidStartBlockPattern() {
     settings.setProperty(IssueExclusionProperties.PATTERNS_BLOCK_KEY, "1");
     settings.setProperty(IssueExclusionProperties.PATTERNS_BLOCK_KEY + ".1." + IssueExclusionProperties.BEGIN_BLOCK_REGEXP, "");
     settings.setProperty(IssueExclusionProperties.PATTERNS_BLOCK_KEY + ".1." + IssueExclusionProperties.END_BLOCK_REGEXP, "// SONAR-ON");
-    patternsInitializer.loadFileContentPatterns();
+    patternsInitializer = new IssueExclusionPatternInitializer(settings);
   }
 
   @Test
@@ -123,7 +92,7 @@ public class IssueExclusionPatternInitializerTest {
     settings.setProperty(IssueExclusionProperties.PATTERNS_ALLFILE_KEY, "1,2");
     settings.setProperty(IssueExclusionProperties.PATTERNS_ALLFILE_KEY + ".1." + IssueExclusionProperties.FILE_REGEXP, "@SONAR-IGNORE-ALL");
     settings.setProperty(IssueExclusionProperties.PATTERNS_ALLFILE_KEY + ".2." + IssueExclusionProperties.FILE_REGEXP, "//FOO-IGNORE-ALL");
-    patternsInitializer.loadFileContentPatterns();
+    patternsInitializer = new IssueExclusionPatternInitializer(settings);
 
     assertThat(patternsInitializer.hasConfiguredPatterns()).isTrue();
     assertThat(patternsInitializer.hasFileContentPattern()).isTrue();
@@ -133,10 +102,10 @@ public class IssueExclusionPatternInitializerTest {
     assertThat(patternsInitializer.getAllFilePatterns().size()).isEqualTo(2);
   }
 
-  @Test(expected = SonarException.class)
+  @Test(expected = IllegalStateException.class)
   public void shouldLogInvalidAllFilePattern() {
     settings.setProperty(IssueExclusionProperties.PATTERNS_ALLFILE_KEY, "1");
     settings.setProperty(IssueExclusionProperties.PATTERNS_ALLFILE_KEY + ".1." + IssueExclusionProperties.FILE_REGEXP, "");
-    patternsInitializer.loadFileContentPatterns();
+    patternsInitializer = new IssueExclusionPatternInitializer(settings);
   }
 }
index de3982e504eaa823dd168697a11653f84e166066..6feecb2863747240726243657f33e0ea0f3aa3c6 100644 (file)
@@ -31,7 +31,6 @@ import static org.assertj.core.api.Assertions.assertThat;
 public class IssueInclusionPatternInitializerTest {
 
   private IssueInclusionPatternInitializer patternsInitializer;
-
   private Settings settings;
 
   @Before
@@ -58,14 +57,6 @@ public class IssueInclusionPatternInitializerTest {
     assertThat(patternsInitializer.hasConfiguredPatterns()).isTrue();
     assertThat(patternsInitializer.hasMulticriteriaPatterns()).isTrue();
     assertThat(patternsInitializer.getMulticriteriaPatterns().size()).isEqualTo(2);
-
-    patternsInitializer.initializePatternsForPath("org/foo/Bar.java", "org.foo.Bar");
-    patternsInitializer.initializePatternsForPath("org/foo/Baz.java", "org.foo.Baz");
-    patternsInitializer.initializePatternsForPath("org/foo/Hello.java", "org.foo.Hello");
-
-    assertThat(patternsInitializer.getPathForComponent("org.foo.Bar")).isEqualTo("org/foo/Bar.java");
-    assertThat(patternsInitializer.getPathForComponent("org.foo.Baz")).isEqualTo("org/foo/Baz.java");
-    assertThat(patternsInitializer.getPathForComponent("org.foo.Hello")).isEqualTo("org/foo/Hello.java");
   }
 
 }
index b14cc76e4a3a0ea9efa5e70788b1cab5e8072a18..d6c6f778b5357a324bc5bce7d9f7251c1ed516a7 100644 (file)
@@ -22,18 +22,23 @@ package org.sonar.scanner.issue.ignore.pattern;
 import org.junit.Test;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.rules.Rule;
-import org.sonar.api.scan.issue.filter.FilterableIssue;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
 
 public class IssuePatternTest {
 
   @Test
   public void shouldMatchLines() {
-    IssuePattern pattern = new IssuePattern("*", "*");
-    pattern.addLine(12).addLine(15).addLineRange(20, 25);
+    Set<LineRange> lineRanges = new HashSet<>();
+    lineRanges.add(new LineRange(12));
+    lineRanges.add(new LineRange(15));
+    lineRanges.add(new LineRange(20, 25));
+
+    IssuePattern pattern = new IssuePattern("*", "*", lineRanges);
 
     assertThat(pattern.matchLine(3)).isFalse();
     assertThat(pattern.matchLine(12)).isTrue();
@@ -77,31 +82,17 @@ public class IssuePatternTest {
     Rule rule = Rule.create("checkstyle", "IllegalRegexp", "");
     String javaFile = "org.foo.Bar";
 
-    IssuePattern pattern = new IssuePattern("*", "*");
-    pattern.addLine(12);
-
-    assertThat(pattern.match(create(rule, javaFile, null))).isFalse();
-    assertThat(pattern.match(create(rule, javaFile, 12))).isTrue();
-    assertThat(pattern.match(create(rule, null, null))).isFalse();
-  }
+    IssuePattern pattern = new IssuePattern("*", "*", Collections.singleton(new LineRange(12)));
 
-  private FilterableIssue create(Rule rule, String component, Integer line) {
-    FilterableIssue mockIssue = mock(FilterableIssue.class);
-    RuleKey ruleKey = null;
-    if (rule != null) {
-      ruleKey = rule.ruleKey();
-    }
-    when(mockIssue.ruleKey()).thenReturn(ruleKey);
-    when(mockIssue.componentKey()).thenReturn(component);
-    when(mockIssue.line()).thenReturn(line);
-    return mockIssue;
+    assertThat(pattern.match(javaFile, rule.ruleKey(), null)).isFalse();
+    assertThat(pattern.match(javaFile, rule.ruleKey(), 12)).isTrue();
+    assertThat(pattern.match(null, rule.ruleKey(), null)).isFalse();
   }
 
   @Test
   public void shouldPrintPatternToString() {
     IssuePattern pattern = new IssuePattern("*", "checkstyle:*");
 
-    assertThat(pattern.toString()).isEqualTo(
-      "IssuePattern[resourcePattern=*,rulePattern=checkstyle:*,lines=[],lineRanges=[],beginBlockRegexp=<null>,endBlockRegexp=<null>,allFileRegexp=<null>,checkLines=true]");
+    assertThat(pattern.toString()).isEqualTo("IssuePattern[resourcePattern=*,rulePattern=checkstyle:*,lines=[],lineRanges=[],checkLines=false]");
   }
 }
index 056451fb3e28ed322d412800981935178873e110..f4ca8b9c745750f2f69ba6202d1de05c4274391e 100644 (file)
  */
 package org.sonar.scanner.issue.ignore.pattern;
 
-import org.junit.Rule;
 import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.api.utils.SonarException;
-import org.sonar.scanner.issue.ignore.pattern.IssuePattern;
 import org.sonar.scanner.issue.ignore.pattern.PatternDecoder;
-import java.util.List;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class PatternDecoderTest {
-
-  private PatternDecoder decoder = new PatternDecoder();
-
-  @Rule
-  public ExpectedException thrown = ExpectedException.none();
-
-  @Test
-  public void shouldReadString() {
-    String patternsList = "# a comment followed by a blank line\n\n" +
-      "# suppress all violations\n" +
-      "*;*;*\n\n" +
-      "# exclude a Java file\n" +
-      "com.foo.Bar;*;*\n\n" +
-      "# exclude a Java package\n" +
-      "com.foo.*;*;*\n\n" +
-      "# exclude a specific rule\n" +
-      "*;checkstyle:IllegalRegexp;*\n\n" +
-      "# exclude a specific rule on a specific file\n" +
-      "com.foo.Bar;checkstyle:IllegalRegexp;*\n";
-    List<IssuePattern> patterns = decoder.decode(patternsList);
-
-    assertThat(patterns).hasSize(5);
-  }
-
   @Test
   public void shouldCheckFormatOfResource() {
     assertThat(PatternDecoder.isResource("")).isFalse();
@@ -83,106 +54,4 @@ public class PatternDecoderTest {
     assertThat(PatternDecoder.isLinesRange("[24-65]")).isTrue();
     assertThat(PatternDecoder.isLinesRange("[13,24-65,84-89,122]")).isTrue();
   }
-
-  @Test
-  public void shouldReadStarPatterns() {
-    IssuePattern pattern = decoder.decodeLine("*;*;*");
-
-    assertThat(pattern.getResourcePattern().toString()).isEqualTo("*");
-    assertThat(pattern.getRulePattern().toString()).isEqualTo("*");
-    assertThat(pattern.isCheckLines()).isFalse();
-  }
-
-  @Test
-  public void shouldReadLineIds() {
-    IssuePattern pattern = decoder.decodeLine("*;*;[10,25,98]");
-
-    assertThat(pattern.isCheckLines()).isTrue();
-    assertThat(pattern.getAllLines()).containsOnly(10, 25, 98);
-  }
-
-  @Test
-  public void shouldReadRangeOfLineIds() {
-    IssuePattern pattern = decoder.decodeLine("*;*;[10-12,25,97-100]");
-
-    assertThat(pattern.isCheckLines()).isTrue();
-    assertThat(pattern.getAllLines()).containsOnly(10, 11, 12, 25, 97, 98, 99, 100);
-  }
-
-  @Test
-  public void shouldNotExcludeLines() {
-    // [] is different than *
-    // - all violations are excluded on *
-    // * no violations are excluded on []
-    IssuePattern pattern = decoder.decodeLine("*;*;[]");
-
-    assertThat(pattern.isCheckLines()).isTrue();
-    assertThat(pattern.getAllLines()).isEmpty();
-  }
-
-  @Test
-  public void shouldReadBlockPattern() {
-    IssuePattern pattern = decoder.decodeLine("SONAR-OFF;SONAR-ON");
-
-    assertThat(pattern.getResourcePattern()).isNull();
-    assertThat(pattern.getBeginBlockRegexp()).isEqualTo("SONAR-OFF");
-    assertThat(pattern.getEndBlockRegexp()).isEqualTo("SONAR-ON");
-  }
-
-  @Test
-  public void shouldReadAllFilePattern() {
-    IssuePattern pattern = decoder.decodeLine("SONAR-ALL-OFF");
-
-    assertThat(pattern.getResourcePattern()).isNull();
-    assertThat(pattern.getAllFileRegexp()).isEqualTo("SONAR-ALL-OFF");
-  }
-
-  @Test
-  public void shouldFailToReadUncorrectLine1() {
-    thrown.expect(SonarException.class);
-    thrown.expectMessage("Exclusions > Issues : Invalid format. The following line has more than 3 fields separated by comma");
-
-    decoder.decode(";;;;");
-  }
-
-  @Test
-  public void shouldFailToReadUncorrectLine3() {
-    thrown.expect(SonarException.class);
-    thrown.expectMessage("Exclusions > Issues : Invalid format. The first field does not define a resource pattern");
-
-    decoder.decode(";*;*");
-  }
-
-  @Test
-  public void shouldFailToReadUncorrectLine4() {
-    thrown.expect(SonarException.class);
-    thrown.expectMessage("Exclusions > Issues : Invalid format. The second field does not define a rule pattern");
-
-    decoder.decode("*;;*");
-  }
-
-  @Test
-  public void shouldFailToReadUncorrectLine5() {
-    thrown.expect(SonarException.class);
-    thrown.expectMessage("Exclusions > Issues : Invalid format. The third field does not define a range of lines");
-
-    decoder.decode("*;*;blabla");
-  }
-
-  @Test
-  public void shouldFailToReadUncorrectLine6() {
-    thrown.expect(SonarException.class);
-    thrown.expectMessage("Exclusions > Issues : Invalid format. The first field does not define a regular expression");
-
-    decoder.decode(";ON");
-  }
-
-  @Test
-  public void shouldAcceptEmptyEndBlockRegexp() {
-    IssuePattern pattern = decoder.decodeLine("OFF;");
-
-    assertThat(pattern.getResourcePattern()).isNull();
-    assertThat(pattern.getBeginBlockRegexp()).isEqualTo("OFF");
-    assertThat(pattern.getEndBlockRegexp()).isEmpty();
-  }
 }
index 2025d0d1fd884cb2e421f1221ddaa5cbf83e8608..ea9cdb5606c6a01b5373efc7aed3906641bbd82e 100644 (file)
  */
 package org.sonar.scanner.issue.ignore.pattern;
 
-import org.sonar.api.scan.issue.filter.FilterableIssue;
 import org.sonar.scanner.issue.ignore.pattern.IssuePattern;
 import org.sonar.scanner.issue.ignore.pattern.LineRange;
-import org.sonar.scanner.issue.ignore.pattern.PatternDecoder;
 import org.sonar.scanner.issue.ignore.pattern.PatternMatcher;
 import com.google.common.collect.Sets;
 import org.junit.Before;
 import org.junit.Test;
-import org.sonar.api.rule.RuleKey;
 import org.sonar.api.rules.Rule;
 
+import java.util.Collections;
 import java.util.Set;
 
+import javax.annotation.Nullable;
+
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
 
 public class PatternMatcherTest {
 
@@ -72,51 +70,47 @@ public class PatternMatcherTest {
 
   @Test
   public void shouldHaveNoMatcherIfNoneDefined() {
-    assertThat(patternMatcher.getMatchingPattern(create(CHECKSTYLE_RULE, JAVA_FILE, null))).isNull();
+    assertThat(patternMatcher.getMatchingPattern(JAVA_FILE, CHECKSTYLE_RULE.ruleKey(), null)).isNull();
   }
 
   @Test
   public void shouldMatchWithStandardPatterns() {
-    patternMatcher.addPatternForComponent(JAVA_FILE, createPattern("org.foo.Hello;checkstyle:MagicNumber;[15-200]"));
+    patternMatcher.addPatternForComponent(JAVA_FILE, createPattern("org.foo.Hello", "checkstyle:MagicNumber", createRanges(15, 200)));
 
-    assertThat(patternMatcher.getMatchingPattern(create(CHECKSTYLE_RULE, JAVA_FILE, 150))).isNotNull();
+    assertThat(patternMatcher.getMatchingPattern(JAVA_FILE, CHECKSTYLE_RULE.ruleKey(), 150)).isNotNull();
   }
 
   @Test
   public void shouldNotMatchWithStandardPatterns() {
-    patternMatcher.addPatternForComponent(JAVA_FILE, createPattern("org.foo.Hello;checkstyle:MagicNumber;[15-200]"));
+    patternMatcher.addPatternForComponent(JAVA_FILE, createPattern("org.foo.Hello", "checkstyle:MagicNumber", createRanges(15, 200)));
 
-    assertThat(patternMatcher.getMatchingPattern(create(CHECKSTYLE_RULE, JAVA_FILE, 5))).isNull();
+    assertThat(patternMatcher.getMatchingPattern(JAVA_FILE, CHECKSTYLE_RULE.ruleKey(), 5)).isNull();
   }
 
   @Test
   public void shouldMatchWithExtraPattern() {
-    patternMatcher.addPatternForComponent(JAVA_FILE, createPattern("org.foo.Hello;*;[15-200]"));
+    patternMatcher.addPatternForComponent(JAVA_FILE, createPattern("org.foo.Hello", "*", createRanges(15, 200)));
 
-    assertThat(patternMatcher.getMatchingPattern(create(CHECKSTYLE_RULE, JAVA_FILE, 150))).isNotNull();
+    assertThat(patternMatcher.getMatchingPattern(JAVA_FILE, CHECKSTYLE_RULE.ruleKey(), 150)).isNotNull();
   }
 
   @Test
   public void shouldNotMatchWithExtraPattern() {
-    patternMatcher.addPatternForComponent(JAVA_FILE, createPattern("org.foo.Hello;*;[15-200]"));
+    patternMatcher.addPatternForComponent(JAVA_FILE, createPattern("org.foo.Hello", "*", createRanges(15, 200)));
 
-    assertThat(patternMatcher.getMatchingPattern(create(CHECKSTYLE_RULE, JAVA_FILE, 5))).isNull();
+    assertThat(patternMatcher.getMatchingPattern(JAVA_FILE, CHECKSTYLE_RULE.ruleKey(), 5)).isNull();
   }
 
-  private FilterableIssue create(Rule rule, String component, Integer line) {
-    FilterableIssue mockIssue = mock(FilterableIssue.class);
-    RuleKey ruleKey = null;
-    if (rule != null) {
-      ruleKey = rule.ruleKey();
+  private IssuePattern createPattern(String resourcePattern, String rulePattern, @Nullable Set<LineRange> lineRanges) {
+    if (lineRanges != null) {
+      return new IssuePattern(resourcePattern, rulePattern, lineRanges);
+    } else {
+      return new IssuePattern(resourcePattern, rulePattern);
     }
-    when(mockIssue.ruleKey()).thenReturn(ruleKey);
-    when(mockIssue.componentKey()).thenReturn(component);
-    when(mockIssue.line()).thenReturn(line);
-    return mockIssue;
   }
 
-  private IssuePattern createPattern(String line) {
-    return new PatternDecoder().decode(line).get(0);
+  private Set<LineRange> createRanges(int from, int to) {
+    return Collections.singleton(new LineRange(from, to));
   }
 
 }
index 1c2922c214164e64b5b82f7befdf69127056653a..638e504b6ce6a962756b6162eeb81d2ff00d538a 100644 (file)
 package org.sonar.scanner.issue.ignore.scanner;
 
 import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Collections;
 
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
-import org.junit.rules.TemporaryFolder;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.internal.DefaultFileSystem;
-import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
 import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer;
-import org.sonar.scanner.issue.ignore.pattern.IssueInclusionPatternInitializer;
+import org.sonar.scanner.issue.ignore.pattern.IssuePattern;
 import org.sonar.scanner.issue.ignore.pattern.PatternMatcher;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
 public class IssueExclusionsLoaderTest {
@@ -52,31 +44,18 @@ public class IssueExclusionsLoaderTest {
   @Rule
   public ExpectedException thrown = ExpectedException.none();
 
-  @Rule
-  public TemporaryFolder temp = new TemporaryFolder();
-
-  @Mock
-  private IssueExclusionsRegexpScanner regexpScanner;
-
-  @Mock
-  private IssueInclusionPatternInitializer inclusionPatternInitializer;
-
   @Mock
   private IssueExclusionPatternInitializer exclusionPatternInitializer;
 
-  @Mock
   private PatternMatcher patternMatcher;
 
-  private DefaultFileSystem fs;
   private IssueExclusionsLoader scanner;
-  private Path baseDir;
 
   @Before
   public void before() throws Exception {
-    baseDir = temp.newFolder().toPath();
-    fs = new DefaultFileSystem(baseDir).setEncoding(UTF_8);
+    patternMatcher = new PatternMatcher();
     MockitoAnnotations.initMocks(this);
-    scanner = new IssueExclusionsLoader(regexpScanner, exclusionPatternInitializer, inclusionPatternInitializer, fs);
+    scanner = new IssueExclusionsLoader(exclusionPatternInitializer, patternMatcher);
   }
 
   @Test
@@ -85,108 +64,55 @@ public class IssueExclusionsLoaderTest {
   }
 
   @Test
-  public void shouldExecute() {
-    when(exclusionPatternInitializer.hasConfiguredPatterns()).thenReturn(true);
-    when(inclusionPatternInitializer.hasConfiguredPatterns()).thenReturn(true);
-    assertThat(scanner.shouldExecute()).isTrue();
+  public void createComputer() {
+    assertThat(scanner.createCharHandlerFor("src/main/java/Foo.java")).isNull();
 
-    when(exclusionPatternInitializer.hasConfiguredPatterns()).thenReturn(true);
-    when(inclusionPatternInitializer.hasConfiguredPatterns()).thenReturn(false);
-    assertThat(scanner.shouldExecute()).isTrue();
+    when(exclusionPatternInitializer.getAllFilePatterns()).thenReturn(Collections.singletonList("pattern"));
+    scanner = new IssueExclusionsLoader(exclusionPatternInitializer, patternMatcher);
+    assertThat(scanner.createCharHandlerFor("src/main/java/Foo.java")).isNotNull();
 
-    when(exclusionPatternInitializer.hasConfiguredPatterns()).thenReturn(false);
-    when(inclusionPatternInitializer.hasConfiguredPatterns()).thenReturn(true);
-    assertThat(scanner.shouldExecute()).isTrue();
 
-    when(exclusionPatternInitializer.hasConfiguredPatterns()).thenReturn(false);
-    when(inclusionPatternInitializer.hasConfiguredPatterns()).thenReturn(false);
-    assertThat(scanner.shouldExecute()).isFalse();
   }
 
   @Test
-  public void shouldAnalyzeProject() throws IOException {
-    Path javaFile1 = baseDir.resolve("src/main/java/Foo.java");
-    fs.add(new TestInputFileBuilder("polop", "src/main/java/Foo.java")
-      .setModuleBaseDir(baseDir)
-      .setCharset(StandardCharsets.UTF_8)
-      .setType(InputFile.Type.MAIN)
-      .build());
-    Path javaTestFile1 = baseDir.resolve("src/test/java/FooTest.java");
-    fs.add(new TestInputFileBuilder("polop", "src/test/java/FooTest.java")
-      .setModuleBaseDir(baseDir)
-      .setCharset(StandardCharsets.UTF_8)
-      .setType(InputFile.Type.TEST)
-      .build());
-
-    when(exclusionPatternInitializer.hasFileContentPattern()).thenReturn(true);
-
-    scanner.preLoadAllFiles();
-
-    verify(inclusionPatternInitializer).initializePatternsForPath("src/main/java/Foo.java", "polop:src/main/java/Foo.java");
-    verify(inclusionPatternInitializer).initializePatternsForPath("src/test/java/FooTest.java", "polop:src/test/java/FooTest.java");
-    verify(exclusionPatternInitializer).initializePatternsForPath("src/main/java/Foo.java", "polop:src/main/java/Foo.java");
-    verify(exclusionPatternInitializer).initializePatternsForPath("src/test/java/FooTest.java", "polop:src/test/java/FooTest.java");
-    verify(regexpScanner).scan("polop:src/main/java/Foo.java", javaFile1, UTF_8);
-    verify(regexpScanner).scan("polop:src/test/java/FooTest.java", javaTestFile1, UTF_8);
-  }
-
-  @Test
-  public void isLoaded() {
-    DefaultInputFile inputFile1 = new TestInputFileBuilder("polop", "src/test/java/FooTest1.java")
-      .setModuleBaseDir(baseDir)
-      .setCharset(StandardCharsets.UTF_8)
-      .setType(InputFile.Type.TEST)
-      .build();
-    DefaultInputFile inputFile2 = new TestInputFileBuilder("polop", "src/test/java/FooTest2.java")
-      .setModuleBaseDir(baseDir)
-      .setCharset(StandardCharsets.UTF_8)
-      .setType(InputFile.Type.TEST)
-      .build();
-
-    when(inclusionPatternInitializer.getPathForComponent(inputFile1.key())).thenReturn(null);
-    when(inclusionPatternInitializer.getPathForComponent(inputFile2.key())).thenReturn("path1");
-
-    assertFalse(scanner.isLoaded(inputFile1));
-    assertTrue(scanner.isLoaded(inputFile2));
-
+  public void shouldHavePatternsBasedOnMulticriteriaPattern() {
+    IssuePattern pattern1 = new IssuePattern("org/foo/Bar.java", "*");
+    IssuePattern pattern2 = new IssuePattern("org/foo/Hello.java", "checkstyle:MagicNumber");
+    when(exclusionPatternInitializer.getMulticriteriaPatterns()).thenReturn(Arrays.asList(new IssuePattern[] {pattern1, pattern2}));
+
+    IssueExclusionsLoader loader = new IssueExclusionsLoader(exclusionPatternInitializer, patternMatcher);
+    loader.addMulticriteriaPatterns("org/foo/Bar.java", "org.foo.Bar");
+    loader.addMulticriteriaPatterns("org/foo/Baz.java", "org.foo.Baz");
+    loader.addMulticriteriaPatterns("org/foo/Hello.java", "org.foo.Hello");
+
+    assertThat(patternMatcher.getPatternsForComponent("org.foo.Bar")).hasSize(1);
+    assertThat(patternMatcher.getPatternsForComponent("org.foo.Baz")).hasSize(0);
+    assertThat(patternMatcher.getPatternsForComponent("org.foo.Hello")).hasSize(1);
   }
 
   @Test
-  public void shouldAnalyseFilesOnlyWhenRegexConfigured() {
-    fs.add(new TestInputFileBuilder("polop", "src/main/java/Foo.java")
-      .setType(InputFile.Type.MAIN)
-      .setCharset(StandardCharsets.UTF_8)
-      .build());
-    fs.add(new TestInputFileBuilder("polop", "src/test/java/FooTest.java")
-      .setType(InputFile.Type.TEST)
-      .setCharset(StandardCharsets.UTF_8)
-      .build());
-    when(exclusionPatternInitializer.hasFileContentPattern()).thenReturn(false);
-
-    scanner.preLoadAllFiles();
-
-    verify(inclusionPatternInitializer).initializePatternsForPath("src/main/java/Foo.java", "polop:src/main/java/Foo.java");
-    verify(inclusionPatternInitializer).initializePatternsForPath("src/test/java/FooTest.java", "polop:src/test/java/FooTest.java");
-    verify(exclusionPatternInitializer).initializePatternsForPath("src/main/java/Foo.java", "polop:src/main/java/Foo.java");
-    verify(exclusionPatternInitializer).initializePatternsForPath("src/test/java/FooTest.java", "polop:src/test/java/FooTest.java");
-    verifyZeroInteractions(regexpScanner);
+  public void shouldAnalyzeProject() throws IOException {
+    IssuePattern pattern = new IssuePattern("**", "*");
+    when(exclusionPatternInitializer.getMulticriteriaPatterns()).thenReturn(Collections.singletonList(pattern));
+    when(exclusionPatternInitializer.hasMulticriteriaPatterns()).thenReturn(true);
+
+    PatternMatcher patternMatcher = mock(PatternMatcher.class);
+    IssueExclusionsLoader loader = new IssueExclusionsLoader(exclusionPatternInitializer, patternMatcher);
+    assertThat(loader.shouldExecute()).isTrue();
+    loader.addMulticriteriaPatterns("src/main/java/Foo.java", "polop:src/main/java/Foo.java");
+    loader.addMulticriteriaPatterns("src/test/java/FooTest.java", "polop:src/test/java/FooTest.java");
+
+    verify(patternMatcher).addPatternForComponent("polop:src/main/java/Foo.java", pattern);
+    verify(patternMatcher).addPatternForComponent("polop:src/test/java/FooTest.java", pattern);
+    verifyNoMoreInteractions(patternMatcher);
   }
 
   @Test
-  public void shouldReportFailure() throws IOException {
-    Path phpFile1 = baseDir.resolve("src/Foo.php");
-    fs.add(new TestInputFileBuilder("polop", "src/Foo.php")
-      .setModuleBaseDir(baseDir)
-      .setType(InputFile.Type.MAIN)
-      .setCharset(StandardCharsets.UTF_8)
-      .build());
-
-    when(exclusionPatternInitializer.hasFileContentPattern()).thenReturn(true);
-    doThrow(new IOException("BUG")).when(regexpScanner).scan("polop:src/Foo.php", phpFile1, UTF_8);
-
-    thrown.expect(IllegalStateException.class);
-    thrown.expectMessage("Unable to read the source file");
+  public void shouldExecute() {
+    when(exclusionPatternInitializer.hasMulticriteriaPatterns()).thenReturn(true);
+    assertThat(scanner.shouldExecute()).isTrue();
 
-    scanner.preLoadAllFiles();
+    when(exclusionPatternInitializer.hasMulticriteriaPatterns()).thenReturn(false);
+    assertThat(scanner.shouldExecute()).isFalse();
   }
 }
index 55581e74adc05d23c1d2dd0ea86731ab1f72c573..37c2b957b655a0b5ea84bad68544d6ba1a0d11d6 100644 (file)
  */
 package org.sonar.scanner.issue.ignore.scanner;
 
-import com.google.common.collect.Sets;
 import com.google.common.io.Resources;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.sonar.api.batch.fs.internal.FileMetadata;
 import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer;
-import org.sonar.scanner.issue.ignore.pattern.IssuePattern;
 import org.sonar.scanner.issue.ignore.pattern.LineRange;
 import org.sonar.scanner.issue.ignore.pattern.PatternMatcher;
 import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsRegexpScanner;
+import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader.DoubleRegexpMatcher;
+
+import java.net.URISyntaxException;
+import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
+import java.util.regex.Pattern;
 
 import static java.nio.charset.StandardCharsets.UTF_8;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
 
 public class IssueExclusionsRegexpScannerTest {
-
-  private IssueExclusionsRegexpScanner regexpScanner;
-
   private String javaFile;
+
   @Mock
   private IssueExclusionPatternInitializer patternsInitializer;
   @Mock
   private PatternMatcher patternMatcher;
-  @Mock
-  private IssuePattern allFilePattern;
-  @Mock
-  private IssuePattern blockPattern1;
-  @Mock
-  private IssuePattern blockPattern2;
+
+  private List<Pattern> allFilePatterns;
+  private List<DoubleRegexpMatcher> blockPatterns;
+  private IssueExclusionsRegexpScanner regexpScanner;
+  private FileMetadata fileMetadata = new FileMetadata();
 
   @Before
   public void init() {
     MockitoAnnotations.initMocks(this);
 
-    when(allFilePattern.getAllFileRegexp()).thenReturn("@SONAR-IGNORE-ALL");
-    when(blockPattern1.getBeginBlockRegexp()).thenReturn("// SONAR-OFF");
-    when(blockPattern1.getEndBlockRegexp()).thenReturn("// SONAR-ON");
-    when(blockPattern2.getBeginBlockRegexp()).thenReturn("// FOO-OFF");
-    when(blockPattern2.getEndBlockRegexp()).thenReturn("// FOO-ON");
-    when(patternsInitializer.getAllFilePatterns()).thenReturn(Arrays.asList(allFilePattern));
-    when(patternsInitializer.getBlockPatterns()).thenReturn(Arrays.asList(blockPattern1, blockPattern2));
-    when(patternsInitializer.getPatternMatcher()).thenReturn(patternMatcher);
-
-    regexpScanner = new IssueExclusionsRegexpScanner(patternsInitializer);
-    verify(patternsInitializer, times(1)).getAllFilePatterns();
-    verify(patternsInitializer, times(1)).getBlockPatterns();
+    blockPatterns = Arrays.asList(new DoubleRegexpMatcher[] {
+      new DoubleRegexpMatcher(Pattern.compile("// SONAR-OFF"), Pattern.compile("// SONAR-ON")),
+      new DoubleRegexpMatcher(Pattern.compile("// FOO-OFF"), Pattern.compile("// FOO-ON"))
+    });
+    allFilePatterns = Collections.singletonList(Pattern.compile("@SONAR-IGNORE-ALL"));
 
     javaFile = "org.sonar.test.MyFile";
+    regexpScanner = new IssueExclusionsRegexpScanner(javaFile, allFilePatterns, blockPatterns, patternMatcher);
+  }
+  
+  @Test
+  public void shouldDetectPatternLastLine() throws URISyntaxException {
+    fileMetadata.readMetadata(getResource("file-with-single-regexp-last-line.txt").toFile(), UTF_8, regexpScanner);
+
+    verify(patternMatcher, times(1)).addPatternToExcludeResource(javaFile);
+    verifyNoMoreInteractions(patternMatcher);
   }
 
   @Test
   public void shouldDoNothing() throws Exception {
-    regexpScanner.scan(javaFile, Paths.get(Resources.getResource(
-      "org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScannerTest/file-with-no-regexp.txt").toURI()), UTF_8);
-
-    verifyNoMoreInteractions(patternsInitializer);
+    fileMetadata.readMetadata(getResource("file-with-no-regexp.txt").toFile(), UTF_8, regexpScanner);
+    verifyNoMoreInteractions(patternMatcher);
   }
 
   @Test
   public void shouldAddPatternToExcludeFile() throws Exception {
-    regexpScanner.scan(javaFile, Paths.get(Resources.getResource(
-      "org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScannerTest/file-with-single-regexp.txt").toURI()), UTF_8);
+    fileMetadata.readMetadata(getResource("file-with-single-regexp.txt").toFile(), UTF_8, regexpScanner);
 
-    verify(patternsInitializer).getPatternMatcher();
     verify(patternMatcher, times(1)).addPatternToExcludeResource(javaFile);
-    verifyNoMoreInteractions(patternsInitializer);
+    verifyNoMoreInteractions(patternMatcher);
   }
 
   @Test
   public void shouldAddPatternToExcludeFileEvenIfAlsoDoubleRegexps() throws Exception {
-    regexpScanner.scan(javaFile, Paths.get(Resources.getResource(
-      "org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScannerTest/file-with-single-regexp-and-double-regexp.txt").toURI()), UTF_8);
+    fileMetadata.readMetadata(getResource("file-with-single-regexp-and-double-regexp.txt").toFile(), UTF_8, regexpScanner);
 
-    verify(patternsInitializer).getPatternMatcher();
+    Set<LineRange> lineRanges = new HashSet<>();
+    lineRanges.add(new LineRange(5, 26));
     verify(patternMatcher, times(1)).addPatternToExcludeResource(javaFile);
-    verifyNoMoreInteractions(patternsInitializer);
+    verify(patternMatcher, times(1)).addPatternToExcludeLines(javaFile, lineRanges);
+    verifyNoMoreInteractions(patternMatcher);
   }
 
   @Test
   public void shouldAddPatternToExcludeLines() throws Exception {
-    regexpScanner.scan(javaFile, Paths.get(Resources.getResource(
-      "org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScannerTest/file-with-double-regexp.txt").toURI()), UTF_8);
+    fileMetadata.readMetadata(getResource("file-with-double-regexp.txt").toFile(), UTF_8, regexpScanner);
 
-    Set<LineRange> lineRanges = Sets.newHashSet();
+    Set<LineRange> lineRanges = new HashSet<>();
     lineRanges.add(new LineRange(21, 25));
-    verify(patternsInitializer).getPatternMatcher();
     verify(patternMatcher, times(1)).addPatternToExcludeLines(javaFile, lineRanges);
-    verifyNoMoreInteractions(patternsInitializer);
+    verifyNoMoreInteractions(patternMatcher);
   }
 
   @Test
   public void shouldAddPatternToExcludeLinesTillTheEnd() throws Exception {
-    regexpScanner.scan(javaFile, Paths.get(Resources.getResource(
-      "org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScannerTest/file-with-double-regexp-unfinished.txt").toURI()), UTF_8);
+    fileMetadata.readMetadata(getResource("file-with-double-regexp-unfinished.txt").toFile(), UTF_8, regexpScanner);
 
-    Set<LineRange> lineRanges = Sets.newHashSet();
+    Set<LineRange> lineRanges = new HashSet<>();
     lineRanges.add(new LineRange(21, 34));
-    verify(patternsInitializer).getPatternMatcher();
     verify(patternMatcher, times(1)).addPatternToExcludeLines(javaFile, lineRanges);
-    verifyNoMoreInteractions(patternsInitializer);
+    verifyNoMoreInteractions(patternMatcher);
   }
 
   @Test
   public void shouldAddPatternToExcludeSeveralLineRanges() throws Exception {
-    regexpScanner.scan(javaFile, Paths.get(Resources.getResource(
-      "org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScannerTest/file-with-double-regexp-twice.txt").toURI()), UTF_8);
+    fileMetadata.readMetadata(getResource("file-with-double-regexp-twice.txt").toFile(), UTF_8, regexpScanner);
 
-    Set<LineRange> lineRanges = Sets.newHashSet();
+    Set<LineRange> lineRanges = new HashSet<>();
     lineRanges.add(new LineRange(21, 25));
     lineRanges.add(new LineRange(29, 33));
-    verify(patternsInitializer).getPatternMatcher();
     verify(patternMatcher, times(1)).addPatternToExcludeLines(javaFile, lineRanges);
-    verifyNoMoreInteractions(patternsInitializer);
+    verifyNoMoreInteractions(patternMatcher);
   }
 
   @Test
   public void shouldAddPatternToExcludeLinesWithWrongOrder() throws Exception {
-    regexpScanner.scan(javaFile, Paths.get(Resources.getResource(
-      "org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScannerTest/file-with-double-regexp-wrong-order.txt").toURI()), UTF_8);
+    fileMetadata.readMetadata(getResource("file-with-double-regexp-wrong-order.txt").toFile(), UTF_8, regexpScanner);
 
-    Set<LineRange> lineRanges = Sets.newHashSet();
+    Set<LineRange> lineRanges = new HashSet<>();
     lineRanges.add(new LineRange(25, 35));
-    verify(patternsInitializer).getPatternMatcher();
     verify(patternMatcher, times(1)).addPatternToExcludeLines(javaFile, lineRanges);
-    verifyNoMoreInteractions(patternsInitializer);
+    verifyNoMoreInteractions(patternMatcher);
   }
 
   @Test
   public void shouldAddPatternToExcludeLinesWithMess() throws Exception {
-    regexpScanner.scan(javaFile, Paths.get(Resources.getResource(
-      "org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScannerTest/file-with-double-regexp-mess.txt").toURI()), UTF_8);
+    fileMetadata.readMetadata(getResource("file-with-double-regexp-mess.txt").toFile(), UTF_8, regexpScanner);
 
-    Set<LineRange> lineRanges = Sets.newHashSet();
+    Set<LineRange> lineRanges = new HashSet<>();
     lineRanges.add(new LineRange(21, 29));
-    verify(patternsInitializer).getPatternMatcher();
     verify(patternMatcher, times(1)).addPatternToExcludeLines(javaFile, lineRanges);
-    verifyNoMoreInteractions(patternsInitializer);
+    verifyNoMoreInteractions(patternMatcher);
+  }
+
+  private Path getResource(String fileName) throws URISyntaxException {
+    return Paths.get(Resources.getResource("org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScannerTest/" + fileName).toURI());
   }
 
 }
index 6f569def50286e21e1cc385add861f19f297b093..d14f205ed8a22ff09110616e19b98926df5bd874 100644 (file)
@@ -349,8 +349,8 @@ public class FileSystemMediumTest {
       .start();
 
     assertThat(logs.getAllAsString()).containsOnlyOnce("'src/myfile.binary' indexed with language 'null'");
-    assertThat(logs.getAllAsString()).doesNotContain("Scanning com.foo.project:src/myfile.binary");
-    assertThat(logs.getAllAsString()).containsOnlyOnce("Scanning com.foo.project:src/sample.xoo");
+    assertThat(logs.getAllAsString()).doesNotContain("'src/myfile.binary' generating issue exclusions");
+    assertThat(logs.getAllAsString()).containsOnlyOnce("'src/sample.xoo' generating issue exclusions");
 
     tester2.stop();
 
@@ -366,7 +366,7 @@ public class FileSystemMediumTest {
     srcDir.mkdir();
 
     File xooFile = new File(srcDir, "sample.xoo");
-    FileUtils.write(xooFile, "Sample xoo\ncontent");
+    FileUtils.write(xooFile, "Sample xoo\npattern");
 
     File unknownFile = new File(srcDir, "myfile.binary");
     FileUtils.write(unknownFile, "some text");
@@ -376,8 +376,9 @@ public class FileSystemMediumTest {
         .put("sonar.sources", "src")
         .build())
       .start();
-
-    assertThat(logs.getAllAsString()).containsOnlyOnce("Scanning com.foo.project:src/myfile.binary");
+    
+    assertThat(logs.getAllAsString()).containsOnlyOnce("- Exclusion pattern 'pattern'");
+    assertThat(logs.getAllAsString()).containsOnlyOnce("'src/myfile.binary' generating issue exclusions");
   }
 
   @Test
index 965540c1047277211ed723f3e206486d22447bbc..c9c7312fab5bad54e901ce12e6e01fd3072ad80c 100644 (file)
@@ -23,6 +23,9 @@ import org.junit.Test;
 import org.mockito.Mockito;
 import org.sonar.api.batch.fs.internal.DefaultInputModule;
 import org.sonar.api.batch.fs.internal.FileMetadata;
+import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer;
+import org.sonar.scanner.issue.ignore.pattern.PatternMatcher;
+import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
@@ -31,8 +34,9 @@ public class MetadataGeneratorProviderTest {
   @Test
   public void create_builder() {
     StatusDetectionFactory statusDetectionFactory = mock(StatusDetectionFactory.class, Mockito.RETURNS_MOCKS);
+    IssueExclusionsLoader issueExclusionsLoader = new IssueExclusionsLoader(mock(IssueExclusionPatternInitializer.class), mock(PatternMatcher.class));
 
     MetadataGeneratorProvider factory = new MetadataGeneratorProvider();
-    assertThat(factory.provide(new DefaultInputModule("module"), statusDetectionFactory, new FileMetadata())).isNotNull();
+    assertThat(factory.provide(new DefaultInputModule("module"), statusDetectionFactory, new FileMetadata(), issueExclusionsLoader)).isNotNull();
   }
 }
index 9fddf40b8e1b850ef5ab653d557c6097434c7a32..67b455a99860635679aad143c98e99217fd82898 100644 (file)
@@ -20,6 +20,7 @@
 package org.sonar.scanner.scan.filesystem;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import java.nio.charset.StandardCharsets;
@@ -40,6 +41,9 @@ import org.sonar.api.batch.fs.internal.DefaultInputModule;
 import org.sonar.api.batch.fs.internal.FileMetadata;
 import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
 import org.sonar.api.utils.PathUtils;
+import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer;
+import org.sonar.scanner.issue.ignore.pattern.PatternMatcher;
+import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
 
 public class MetadataGeneratorTest {
   @Rule
@@ -57,7 +61,8 @@ public class MetadataGeneratorTest {
   public void setUp() {
     MockitoAnnotations.initMocks(this);
     metadata = new FileMetadata();
-    generator = new MetadataGenerator(new DefaultInputModule("module"), statusDetection, metadata);
+    IssueExclusionsLoader issueExclusionsLoader = new IssueExclusionsLoader(mock(IssueExclusionPatternInitializer.class), mock(PatternMatcher.class));
+    generator = new MetadataGenerator(new DefaultInputModule("module"), statusDetection, metadata, issueExclusionsLoader);
   }
 
   @Test
diff --git a/sonar-scanner-engine/src/test/resources/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScannerTest/file-with-single-regexp-last-line.txt b/sonar-scanner-engine/src/test/resources/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScannerTest/file-with-single-regexp-last-line.txt
new file mode 100644 (file)
index 0000000..ef135eb
--- /dev/null
@@ -0,0 +1,33 @@
+package org.sonar.plugins.switchoffviolations.pattern;
+
+import com.google.common.collect.Sets;
+
+import java.util.Set;
+
+/**
+ * @SONAR-IGNORE-ALL
+ */
+public class LineRange {
+  int from, to;
+
+  public LineRange(int from, int to) {
+    if (to < from) {
+      throw new IllegalArgumentException("Line range is not valid: " + from + " must be greater than " + to);
+    }
+    this.from = from;
+    this.to = to;
+  }
+
+  public boolean in(int lineId) {
+    return from <= lineId && lineId <= to;
+  }
+
+  public Set<Integer> toLines() {
+    Set<Integer> lines = Sets.newLinkedHashSet();
+    for (int index = from; index <= to; index++) {
+      lines.add(index);
+    }
+    return lines;
+  }
+
+}
\ No newline at end of file
index ef135ebc50c7b11e00c29ca15845d7417f8e0952..88ad675955fa22a1e322c4ec7d75ab02f1343d4d 100644 (file)
@@ -4,9 +4,6 @@ import com.google.common.collect.Sets;
 
 import java.util.Set;
 
-/**
- * @SONAR-IGNORE-ALL
- */
 public class LineRange {
   int from, to;
 
@@ -30,4 +27,5 @@ public class LineRange {
     return lines;
   }
 
-}
\ No newline at end of file
+}
+// @SONAR-IGNORE-ALL
\ No newline at end of file