From bbff7949d06677e808d7c6f2cf4fd7cfc1f1a079 Mon Sep 17 00:00:00 2001 From: Julien HENRY Date: Fri, 14 Dec 2018 19:35:50 +0100 Subject: SONAR-11587 Rework issue exclusions --- .../scanner/issue/DefaultFilterableIssue.java | 13 ++- .../java/org/sonar/scanner/issue/IssueFilters.java | 5 +- .../org/sonar/scanner/issue/IssuePublisher.java | 2 +- .../scanner/issue/ignore/EnforceIssuesFilter.java | 55 +++++++----- .../scanner/issue/ignore/IgnoreIssuesFilter.java | 51 +++++++---- .../ignore/pattern/AbstractPatternInitializer.java | 16 ++-- .../pattern/IssueExclusionPatternInitializer.java | 14 ++- .../pattern/IssueInclusionPatternInitializer.java | 4 +- .../scanner/issue/ignore/pattern/IssuePattern.java | 90 ++----------------- .../issue/ignore/pattern/PatternDecoder.java | 100 --------------------- .../issue/ignore/pattern/PatternMatcher.java | 62 ------------- .../ignore/scanner/IssueExclusionsLoader.java | 44 ++++++--- .../scanner/IssueExclusionsRegexpScanner.java | 32 ++++--- .../sonar/scanner/scan/ProjectReactorBuilder.java | 42 +++++++-- .../sonar/scanner/scan/ProjectScanContainer.java | 3 - .../sonar/scanner/scan/filesystem/FileIndexer.java | 4 +- .../scanner/scan/filesystem/MetadataGenerator.java | 2 +- 17 files changed, 194 insertions(+), 345 deletions(-) delete mode 100644 sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/PatternDecoder.java delete mode 100644 sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/PatternMatcher.java (limited to 'sonar-scanner-engine/src/main/java/org/sonar/scanner') diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/DefaultFilterableIssue.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/DefaultFilterableIssue.java index eaf4e0f1edb..bb92a02f31c 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/DefaultFilterableIssue.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/DefaultFilterableIssue.java @@ -23,6 +23,7 @@ import java.util.Date; import javax.annotation.concurrent.ThreadSafe; import org.apache.commons.lang.builder.ToStringBuilder; import org.apache.commons.lang.builder.ToStringStyle; +import org.sonar.api.batch.fs.InputComponent; import org.sonar.api.batch.fs.TextRange; import org.sonar.api.batch.fs.internal.DefaultInputProject; import org.sonar.api.batch.fs.internal.DefaultTextPointer; @@ -35,20 +36,20 @@ import org.sonar.scanner.protocol.output.ScannerReport.Issue; @ThreadSafe public class DefaultFilterableIssue implements FilterableIssue { private final Issue rawIssue; + private final InputComponent component; private final ProjectAnalysisInfo projectAnalysisInfo; - private final String componentKey; private DefaultInputProject project; - public DefaultFilterableIssue(DefaultInputProject project, ProjectAnalysisInfo projectAnalysisInfo, Issue rawIssue, String componentKey) { + public DefaultFilterableIssue(DefaultInputProject project, ProjectAnalysisInfo projectAnalysisInfo, Issue rawIssue, InputComponent component) { this.project = project; this.projectAnalysisInfo = projectAnalysisInfo; this.rawIssue = rawIssue; - this.componentKey = componentKey; + this.component = component; } @Override public String componentKey() { - return componentKey; + return component.key(); } @Override @@ -98,6 +99,10 @@ public class DefaultFilterableIssue implements FilterableIssue { return project.key(); } + public InputComponent getComponent() { + return component; + } + @Override public String toString() { return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE); diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/IssueFilters.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/IssueFilters.java index 92a8f758249..b4ade123839 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/IssueFilters.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/IssueFilters.java @@ -19,6 +19,7 @@ */ package org.sonar.scanner.issue; +import org.sonar.api.batch.fs.InputComponent; import org.sonar.api.batch.fs.internal.DefaultInputProject; import org.sonar.api.scan.issue.filter.FilterableIssue; import org.sonar.api.scan.issue.filter.IssueFilter; @@ -45,8 +46,8 @@ public class IssueFilters { this(project, projectAnalysisInfo, new IssueFilter[0]); } - public boolean accept(String componentKey, ScannerReport.Issue rawIssue) { - FilterableIssue fIssue = new DefaultFilterableIssue(project, projectAnalysisInfo, rawIssue, componentKey); + public boolean accept(InputComponent component, ScannerReport.Issue rawIssue) { + FilterableIssue fIssue = new DefaultFilterableIssue(project, projectAnalysisInfo, rawIssue, component); return filterChain.accept(fIssue); } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/IssuePublisher.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/IssuePublisher.java index ca0a8cc0764..f8a652553ea 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/IssuePublisher.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/IssuePublisher.java @@ -70,7 +70,7 @@ public class IssuePublisher { ScannerReport.Issue rawIssue = createReportIssue(issue, inputComponent.scannerId(), activeRule.severity()); - if (filters.accept(inputComponent.key(), rawIssue)) { + if (filters.accept(inputComponent, rawIssue)) { write(inputComponent.scannerId(), rawIssue); return true; } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/EnforceIssuesFilter.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/EnforceIssuesFilter.java index 3f5b74f2390..0cf870ea06b 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/EnforceIssuesFilter.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/EnforceIssuesFilter.java @@ -22,31 +22,31 @@ package org.sonar.scanner.issue.ignore; import java.util.ArrayList; import java.util.Collections; import java.util.List; - -import javax.annotation.CheckForNull; import javax.annotation.concurrent.ThreadSafe; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.sonar.api.batch.fs.InputComponent; -import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.fs.internal.DefaultInputFile; +import org.sonar.api.notifications.AnalysisWarnings; import org.sonar.api.scan.issue.filter.FilterableIssue; import org.sonar.api.scan.issue.filter.IssueFilter; import org.sonar.api.scan.issue.filter.IssueFilterChain; +import org.sonar.api.utils.log.Logger; +import org.sonar.api.utils.log.Loggers; +import org.sonar.scanner.issue.DefaultFilterableIssue; import org.sonar.scanner.issue.ignore.pattern.IssueInclusionPatternInitializer; import org.sonar.scanner.issue.ignore.pattern.IssuePattern; -import org.sonar.scanner.scan.filesystem.InputComponentStore; @ThreadSafe public class EnforceIssuesFilter implements IssueFilter { - private static final Logger LOG = LoggerFactory.getLogger(EnforceIssuesFilter.class); + private static final Logger LOG = Loggers.get(EnforceIssuesFilter.class); private final List multicriteriaPatterns; - private final InputComponentStore componentStore; + private final AnalysisWarnings analysisWarnings; + + private boolean warnDeprecatedIssuePatternAlreadyLogged; - public EnforceIssuesFilter(IssueInclusionPatternInitializer patternInitializer, InputComponentStore componentStore) { + public EnforceIssuesFilter(IssueInclusionPatternInitializer patternInitializer, AnalysisWarnings analysisWarnings) { this.multicriteriaPatterns = Collections.unmodifiableList(new ArrayList<>(patternInitializer.getMulticriteriaPatterns())); - this.componentStore = componentStore; + this.analysisWarnings = analysisWarnings; } @Override @@ -56,12 +56,22 @@ public class EnforceIssuesFilter implements IssueFilter { IssuePattern matchingPattern = null; for (IssuePattern pattern : multicriteriaPatterns) { - if (pattern.getRulePattern().match(issue.ruleKey().toString())) { + if (pattern.matchRule(issue.ruleKey())) { atLeastOneRuleMatched = true; - String relativePath = getRelativePath(issue.componentKey()); - if (relativePath != null && pattern.getResourcePattern().match(relativePath)) { - atLeastOnePatternFullyMatched = true; - matchingPattern = pattern; + InputComponent component = ((DefaultFilterableIssue) issue).getComponent(); + if (component.isFile()) { + DefaultInputFile file = (DefaultInputFile) component; + if (pattern.matchFile(file.getProjectRelativePath())) { + atLeastOnePatternFullyMatched = true; + matchingPattern = pattern; + } else if (pattern.matchFile(file.getModuleRelativePath())) { + warnOnceDeprecatedIssuePattern( + "Specifying module-relative paths at project level in property '" + IssueInclusionPatternInitializer.CONFIG_KEY + "' is deprecated. " + + "To continue matching files like '" + file.getProjectRelativePath() + "', update this property so that patterns refer to project-relative paths."); + + atLeastOnePatternFullyMatched = true; + matchingPattern = pattern; + } } } } @@ -76,13 +86,12 @@ public class EnforceIssuesFilter implements IssueFilter { } } - @CheckForNull - private String getRelativePath(String componentKey) { - InputComponent component = componentStore.getByKey(componentKey); - if (component == null || !component.isFile()) { - return null; + private void warnOnceDeprecatedIssuePattern(String msg) { + if (!warnDeprecatedIssuePatternAlreadyLogged) { + LOG.warn(msg); + analysisWarnings.addUnique(msg); + warnDeprecatedIssuePatternAlreadyLogged = true; } - InputFile inputPath = (InputFile) component; - return inputPath.relativePath(); } + } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/IgnoreIssuesFilter.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/IgnoreIssuesFilter.java index 723d7eecc4d..666b1732dea 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/IgnoreIssuesFilter.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/IgnoreIssuesFilter.java @@ -19,42 +19,55 @@ */ package org.sonar.scanner.issue.ignore; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.google.common.collect.LinkedHashMultimap; +import com.google.common.collect.Multimap; +import org.sonar.api.batch.fs.InputComponent; +import org.sonar.api.batch.fs.internal.DefaultInputFile; import org.sonar.api.scan.issue.filter.FilterableIssue; import org.sonar.api.scan.issue.filter.IssueFilter; import org.sonar.api.scan.issue.filter.IssueFilterChain; -import org.sonar.scanner.issue.ignore.pattern.IssuePattern; -import org.sonar.scanner.issue.ignore.pattern.PatternMatcher; +import org.sonar.api.utils.WildcardPattern; +import org.sonar.api.utils.log.Logger; +import org.sonar.api.utils.log.Loggers; +import org.sonar.scanner.issue.DefaultFilterableIssue; public class IgnoreIssuesFilter implements IssueFilter { - private PatternMatcher patternMatcher; + private Multimap rulePatternByComponent = LinkedHashMultimap.create(); - private static final Logger LOG = LoggerFactory.getLogger(IgnoreIssuesFilter.class); - - public IgnoreIssuesFilter(PatternMatcher patternMatcher) { - this.patternMatcher = patternMatcher; - } + private static final Logger LOG = Loggers.get(IgnoreIssuesFilter.class); @Override public boolean accept(FilterableIssue issue, IssueFilterChain chain) { - if (hasMatchFor(issue)) { + InputComponent component = ((DefaultFilterableIssue) issue).getComponent(); + if (component.isFile() && ((DefaultInputFile) component).isIgnoreAllIssues()) { + return false; + } + if (component.isFile() && ((DefaultInputFile) component).isIgnoreAllIssuesOnLine(issue.line())) { + return false; + } + if (hasRuleMatchFor(component, issue)) { return false; } return chain.accept(issue); } - private boolean hasMatchFor(FilterableIssue issue) { - IssuePattern pattern = patternMatcher.getMatchingPattern(issue.componentKey(), issue.ruleKey(), issue.line()); - if (pattern != null) { - logExclusion(issue, pattern); - return true; + public void addRuleExclusionPatternForComponent(DefaultInputFile inputFile, WildcardPattern rulePattern) { + if ("*".equals(rulePattern.toString())) { + inputFile.setIgnoreAllIssues(true); + } else { + rulePatternByComponent.put(inputFile, rulePattern); } - return false; } - private static void logExclusion(FilterableIssue issue, IssuePattern pattern) { - LOG.debug("Issue {} ignored by exclusion pattern {}", issue, pattern); + private boolean hasRuleMatchFor(InputComponent component, FilterableIssue issue) { + for (WildcardPattern pattern : rulePatternByComponent.get(component)) { + if (pattern.match(issue.ruleKey().toString())) { + LOG.debug("Issue {} ignored by exclusion pattern {}", issue, pattern); + return true; + } + } + return false; + } } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/AbstractPatternInitializer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/AbstractPatternInitializer.java index 51058404811..4b85daf89e4 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/AbstractPatternInitializer.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/AbstractPatternInitializer.java @@ -22,9 +22,9 @@ package org.sonar.scanner.issue.ignore.pattern; import com.google.common.annotations.VisibleForTesting; import java.util.ArrayList; import java.util.List; -import java.util.Set; import org.apache.commons.lang.StringUtils; import org.sonar.api.config.Configuration; +import org.sonar.api.utils.MessageException; import static com.google.common.base.MoreObjects.firstNonNull; @@ -59,13 +59,15 @@ public abstract class AbstractPatternInitializer { multicriteriaPatterns = new ArrayList<>(); for (String id : settings.getStringArray(getMulticriteriaConfigurationKey())) { String propPrefix = getMulticriteriaConfigurationKey() + "." + id + "."; - String resourceKeyPattern = settings.get(propPrefix + "resourceKey").orElse(null); + String filePathPattern = settings.get(propPrefix + "resourceKey").orElse(null); + if (StringUtils.isBlank(filePathPattern)) { + throw MessageException.of("Issue exclusions are misconfigured. File pattern is mandatory for each entry of '" + getMulticriteriaConfigurationKey() + "'"); + } String ruleKeyPattern = settings.get(propPrefix + "ruleKey").orElse(null); - String lineRange = "*"; - String[] fields = new String[] {resourceKeyPattern, ruleKeyPattern, lineRange}; - PatternDecoder.checkRegularLineConstraints(StringUtils.join(fields, ","), fields); - Set rangeOfLines = PatternDecoder.decodeRangeOfLines(firstNonNull(lineRange, "*")); - IssuePattern pattern = new IssuePattern(firstNonNull(resourceKeyPattern, "*"), firstNonNull(ruleKeyPattern, "*"), rangeOfLines); + if (StringUtils.isBlank(ruleKeyPattern)) { + throw MessageException.of("Issue exclusions are misconfigured. Rule key pattern is mandatory for each entry of '" + getMulticriteriaConfigurationKey() + "'"); + } + IssuePattern pattern = new IssuePattern(firstNonNull(filePathPattern, "*"), firstNonNull(ruleKeyPattern, "*")); multicriteriaPatterns.add(pattern); } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssueExclusionPatternInitializer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssueExclusionPatternInitializer.java index 01e0ab76b06..16c3163cbf7 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssueExclusionPatternInitializer.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssueExclusionPatternInitializer.java @@ -24,12 +24,14 @@ import java.util.Collections; import java.util.List; import org.apache.commons.lang.StringUtils; import org.sonar.api.config.Configuration; +import org.sonar.api.utils.MessageException; import org.sonar.core.config.IssueExclusionProperties; import static com.google.common.base.Strings.nullToEmpty; public class IssueExclusionPatternInitializer extends AbstractPatternInitializer { + public static final String CONFIG_KEY = IssueExclusionProperties.EXCLUSION_KEY_PREFIX + ".multicriteria"; private List blockPatterns; private List allFilePatterns; @@ -40,7 +42,7 @@ public class IssueExclusionPatternInitializer extends AbstractPatternInitializer @Override protected String getMulticriteriaConfigurationKey() { - return IssueExclusionProperties.EXCLUSION_KEY_PREFIX + ".multicriteria"; + return CONFIG_KEY; } @Override @@ -54,9 +56,11 @@ public class IssueExclusionPatternInitializer extends AbstractPatternInitializer for (String id : getSettings().getStringArray(IssueExclusionProperties.PATTERNS_BLOCK_KEY)) { String propPrefix = IssueExclusionProperties.PATTERNS_BLOCK_KEY + "." + id + "."; String beginBlockRegexp = getSettings().get(propPrefix + IssueExclusionProperties.BEGIN_BLOCK_REGEXP).orElse(null); + if (StringUtils.isBlank(beginBlockRegexp)) { + throw MessageException.of("Issue exclusions are misconfigured. Start block regexp is mandatory for each entry of '" + IssueExclusionProperties.PATTERNS_BLOCK_KEY + "'"); + } String endBlockRegexp = getSettings().get(propPrefix + IssueExclusionProperties.END_BLOCK_REGEXP).orElse(null); - String[] fields = new String[] {beginBlockRegexp, endBlockRegexp}; - PatternDecoder.checkDoubleRegexpLineConstraints(StringUtils.join(fields, ","), fields); + // As per configuration help, missing second field means: from start regexp to EOF BlockIssuePattern pattern = new BlockIssuePattern(nullToEmpty(beginBlockRegexp), nullToEmpty(endBlockRegexp)); blockPatterns.add(pattern); } @@ -67,7 +71,9 @@ public class IssueExclusionPatternInitializer extends AbstractPatternInitializer for (String id : getSettings().getStringArray(IssueExclusionProperties.PATTERNS_ALLFILE_KEY)) { String propPrefix = IssueExclusionProperties.PATTERNS_ALLFILE_KEY + "." + id + "."; String allFileRegexp = getSettings().get(propPrefix + IssueExclusionProperties.FILE_REGEXP).orElse(null); - PatternDecoder.checkWholeFileRegexp(allFileRegexp); + if (StringUtils.isBlank(allFileRegexp)) { + throw MessageException.of("Issue exclusions are misconfigured. Remove blank entries from '" + IssueExclusionProperties.PATTERNS_ALLFILE_KEY + "'"); + } allFilePatterns.add(nullToEmpty(allFileRegexp)); } allFilePatterns = Collections.unmodifiableList(allFilePatterns); diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssueInclusionPatternInitializer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssueInclusionPatternInitializer.java index 0fa72da96db..30987808e9d 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssueInclusionPatternInitializer.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssueInclusionPatternInitializer.java @@ -24,12 +24,14 @@ import org.sonar.core.config.IssueExclusionProperties; public class IssueInclusionPatternInitializer extends AbstractPatternInitializer { + public static final String CONFIG_KEY = IssueExclusionProperties.INCLUSION_KEY_PREFIX + ".multicriteria"; + public IssueInclusionPatternInitializer(Configuration settings) { super(settings); } @Override protected String getMulticriteriaConfigurationKey() { - return IssueExclusionProperties.INCLUSION_KEY_PREFIX + ".multicriteria"; + return CONFIG_KEY; } } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssuePattern.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssuePattern.java index 4e76159ab72..9be0fd7c75e 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssuePattern.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssuePattern.java @@ -19,108 +19,32 @@ */ package org.sonar.scanner.issue.ignore.pattern; -import java.util.Collections; -import java.util.LinkedHashSet; -import java.util.Set; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; -import org.apache.commons.lang.builder.ToStringBuilder; -import org.apache.commons.lang.builder.ToStringStyle; import org.sonar.api.rule.RuleKey; import org.sonar.api.utils.WildcardPattern; @Immutable public class IssuePattern { - private final WildcardPattern resourcePattern; + private final WildcardPattern filePattern; private final WildcardPattern rulePattern; - private final Set lines; - private final Set lineRanges; - private final boolean checkLines; - public IssuePattern(String resourcePattern, String rulePattern) { - this(resourcePattern, rulePattern, Collections.emptySet()); - } - - public IssuePattern(String resourcePattern, String rulePattern, Set lineRanges) { - this.resourcePattern = WildcardPattern.create(resourcePattern); + public IssuePattern(String filePattern, String rulePattern) { + this.filePattern = WildcardPattern.create(filePattern); this.rulePattern = WildcardPattern.create(rulePattern); - this.checkLines = !lineRanges.isEmpty(); - Set modifiableLines = new LinkedHashSet<>(); - Set modifiableLineRanges = new LinkedHashSet<>(); - - for (LineRange range : lineRanges) { - if (range.from() == range.to()) { - modifiableLines.add(range.from()); - } else { - modifiableLineRanges.add(range); - } - } - - this.lines = Collections.unmodifiableSet(modifiableLines); - this.lineRanges = Collections.unmodifiableSet(modifiableLineRanges); - } - - public WildcardPattern getResourcePattern() { - return resourcePattern; } public WildcardPattern getRulePattern() { return rulePattern; } - boolean isCheckLines() { - return checkLines; - } - - Set getAllLines() { - Set allLines = new LinkedHashSet<>(lines); - for (LineRange lineRange : lineRanges) { - allLines.addAll(lineRange.toLines()); - } - return allLines; + public boolean matchRule(RuleKey rule) { + return rulePattern.match(rule.toString()); } - public boolean match(@Nullable String componentKey, RuleKey ruleKey, @Nullable Integer line) { - if (checkLines) { - if (line == null) { - return false; - } else { - return matchResource(componentKey) && matchRule(ruleKey) && matchLine(line); - } - } - return matchResource(componentKey) && matchRule(ruleKey); + public boolean matchFile(@Nullable String filePath) { + return filePath != null && filePattern.match(filePath); } - boolean matchLine(int lineId) { - if (lines.contains(lineId)) { - return true; - } - - for (LineRange range : lineRanges) { - if (range.in(lineId)) { - return true; - } - } - - return false; - } - - boolean matchRule(RuleKey rule) { - String key = new StringBuilder().append(rule.repository()).append(':').append(rule.rule()).toString(); - return rulePattern.match(key); - } - - public boolean matchResource(@Nullable String resource) { - return resource != null && resourcePattern.match(resource); - } - - public IssuePattern forResource(String resource) { - return new IssuePattern(resource, rulePattern.toString(), lineRanges); - } - - @Override - public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE); - } } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/PatternDecoder.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/PatternDecoder.java deleted file mode 100644 index bb301e3f57b..00000000000 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/PatternDecoder.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 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; - -import com.google.common.annotations.VisibleForTesting; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; -import org.apache.commons.lang.StringUtils; - -public class PatternDecoder { - private static final String LINE_RANGE_REGEXP = "\\[((\\d+|\\d+-\\d+),?)*\\]"; - private static final String CONFIG_FORMAT_ERROR_PREFIX = "Exclusions > Issues : Invalid format. "; - - private PatternDecoder() { - // static only - } - - static void checkRegularLineConstraints(String line, String[] fields) { - if (!isResource(fields[0])) { - throw new IllegalStateException(CONFIG_FORMAT_ERROR_PREFIX + "The first field does not define a resource pattern: " + line); - } - if (!isRule(fields[1])) { - throw new IllegalStateException(CONFIG_FORMAT_ERROR_PREFIX + "The second field does not define a rule pattern: " + line); - } - if (!isLinesRange(fields[2])) { - 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 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 IllegalStateException(CONFIG_FORMAT_ERROR_PREFIX + "The field does not define a regular expression: " + regexp); - } - } - - public static Set decodeRangeOfLines(String field) { - if (StringUtils.equals(field, "*")) { - return Collections.emptySet(); - } else { - Set 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, '-'); - lineRanges.add(new LineRange(Integer.valueOf(range[0]), Integer.valueOf(range[1]))); - } else { - lineRanges.add(new LineRange(Integer.valueOf(part), Integer.valueOf(part))); - } - } - return lineRanges; - } - } - - @VisibleForTesting - static boolean isLinesRange(String field) { - return StringUtils.equals(field, "*") || java.util.regex.Pattern.matches(LINE_RANGE_REGEXP, field); - } - - @VisibleForTesting - static boolean isResource(String field) { - return StringUtils.isNotBlank(field); - } - - @VisibleForTesting - static boolean isRule(String field) { - return StringUtils.isNotBlank(field); - } - - @VisibleForTesting - static boolean isRegexp(String field) { - return StringUtils.isNotBlank(field); - } -} diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/PatternMatcher.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/PatternMatcher.java deleted file mode 100644 index a9be53e5aa0..00000000000 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/PatternMatcher.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 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; - -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.Set; -import javax.annotation.CheckForNull; -import javax.annotation.Nullable; -import org.sonar.api.rule.RuleKey; - -public class PatternMatcher { - - private Multimap excludePatternByComponent = LinkedHashMultimap.create(); - - @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 null; - } - - @VisibleForTesting - public Collection getPatternsForComponent(String componentKey) { - return excludePatternByComponent.get(componentKey); - } - - public void addPatternForComponent(String componentKey, IssuePattern pattern) { - excludePatternByComponent.put(componentKey, pattern.forResource(componentKey)); - } - - public void addPatternToExcludeResource(String componentKey) { - addPatternForComponent(componentKey, new IssuePattern(componentKey, "*")); - } - - public void addPatternToExcludeLines(String componentKey, Set lineRanges) { - addPatternForComponent(componentKey, new IssuePattern(componentKey, "*", lineRanges)); - } - -} diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsLoader.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsLoader.java index 7a3591af10c..6e639385b09 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsLoader.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsLoader.java @@ -23,22 +23,31 @@ 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.DefaultInputFile; import org.sonar.api.batch.fs.internal.charhandler.CharHandler; +import org.sonar.api.notifications.AnalysisWarnings; +import org.sonar.api.utils.log.Logger; +import org.sonar.api.utils.log.Loggers; +import org.sonar.scanner.issue.ignore.IgnoreIssuesFilter; import org.sonar.scanner.issue.ignore.pattern.BlockIssuePattern; import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer; import org.sonar.scanner.issue.ignore.pattern.IssuePattern; -import org.sonar.scanner.issue.ignore.pattern.PatternMatcher; public final class IssueExclusionsLoader { + private static final Logger LOG = Loggers.get(IssueExclusionsLoader.class); + private final List allFilePatterns; private final List blockMatchers; - private final PatternMatcher patternMatcher; + private final IgnoreIssuesFilter ignoreIssuesFilter; + private final AnalysisWarnings analysisWarnings; private final IssueExclusionPatternInitializer patternsInitializer; private final boolean enableCharHandler; + private boolean warnDeprecatedIssuePatternAlreadyLogged; - public IssueExclusionsLoader(IssueExclusionPatternInitializer patternsInitializer, PatternMatcher patternMatcher) { + public IssueExclusionsLoader(IssueExclusionPatternInitializer patternsInitializer, IgnoreIssuesFilter ignoreIssuesFilter, AnalysisWarnings analysisWarnings) { this.patternsInitializer = patternsInitializer; - this.patternMatcher = patternMatcher; + this.ignoreIssuesFilter = ignoreIssuesFilter; + this.analysisWarnings = analysisWarnings; this.allFilePatterns = new ArrayList<>(); this.blockMatchers = new ArrayList<>(); @@ -53,22 +62,31 @@ public final class IssueExclusionsLoader { enableCharHandler = !allFilePatterns.isEmpty() || !blockMatchers.isEmpty(); } - public boolean shouldExecute() { - return patternsInitializer.hasMulticriteriaPatterns(); - } - - public void addMulticriteriaPatterns(String relativePath, String componentKey) { + public void addMulticriteriaPatterns(DefaultInputFile inputFile) { for (IssuePattern pattern : patternsInitializer.getMulticriteriaPatterns()) { - if (pattern.matchResource(relativePath)) { - patternMatcher.addPatternForComponent(componentKey, pattern); + if (pattern.matchFile(inputFile.getProjectRelativePath())) { + ignoreIssuesFilter.addRuleExclusionPatternForComponent(inputFile, pattern.getRulePattern()); + } else if (pattern.matchFile(inputFile.getModuleRelativePath())) { + warnOnceDeprecatedIssuePattern( + "Specifying module-relative paths at project level in property '" + IssueExclusionPatternInitializer.CONFIG_KEY + "' is deprecated. " + + "To continue matching files like '" + inputFile.getProjectRelativePath() + "', update this property so that patterns refer to project-relative paths."); + ignoreIssuesFilter.addRuleExclusionPatternForComponent(inputFile, pattern.getRulePattern()); } } } + private void warnOnceDeprecatedIssuePattern(String msg) { + if (!warnDeprecatedIssuePatternAlreadyLogged) { + LOG.warn(msg); + analysisWarnings.addUnique(msg); + warnDeprecatedIssuePatternAlreadyLogged = true; + } + } + @CheckForNull - public CharHandler createCharHandlerFor(String componentKey) { + public CharHandler createCharHandlerFor(DefaultInputFile inputFile) { if (enableCharHandler) { - return new IssueExclusionsRegexpScanner(componentKey, allFilePatterns, blockMatchers, patternMatcher); + return new IssueExclusionsRegexpScanner(inputFile, allFilePatterns, blockMatchers); } return null; } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScanner.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScanner.java index 5daf24c6075..a08ba55a593 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScanner.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScanner.java @@ -24,12 +24,12 @@ import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.regex.Pattern; -import org.apache.commons.lang.StringUtils; +import java.util.stream.Collectors; +import org.sonar.api.batch.fs.internal.DefaultInputFile; import org.sonar.api.batch.fs.internal.charhandler.CharHandler; import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Loggers; 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 { @@ -38,8 +38,7 @@ public class IssueExclusionsRegexpScanner extends CharHandler { private final StringBuilder sb = new StringBuilder(); private final List allFilePatterns; private final List blockMatchers; - private final String componentKey; - private final PatternMatcher patternMatcher; + private final DefaultInputFile inputFile; private int lineIndex = 1; private List lineExclusions = new ArrayList<>(); @@ -47,22 +46,26 @@ public class IssueExclusionsRegexpScanner extends CharHandler { private int fileLength = 0; private DoubleRegexpMatcher currentMatcher; - IssueExclusionsRegexpScanner(String componentKey, List allFilePatterns, List blockMatchers, PatternMatcher patternMatcher) { + IssueExclusionsRegexpScanner(DefaultInputFile inputFile, List allFilePatterns, List blockMatchers) { this.allFilePatterns = allFilePatterns; this.blockMatchers = blockMatchers; - this.patternMatcher = patternMatcher; - this.componentKey = componentKey; - String relativePath = StringUtils.substringAfterLast(componentKey, ":"); - LOG.info("'{}' generating issue exclusions", relativePath); + this.inputFile = inputFile; + LOG.debug("Evaluate issue exclusions for '{}'", inputFile.getProjectRelativePath()); } @Override public void handleIgnoreEoL(char c) { + if (inputFile.isIgnoreAllIssues()) { + return; + } sb.append(c); } @Override public void newLine() { + if (inputFile.isIgnoreAllIssues()) { + return; + } processLine(sb.toString()); sb.setLength(0); lineIndex++; @@ -70,6 +73,9 @@ public class IssueExclusionsRegexpScanner extends CharHandler { @Override public void eof() { + if (inputFile.isIgnoreAllIssues()) { + return; + } processLine(sb.toString()); if (currentMatcher != null && !currentMatcher.hasSecondPattern()) { @@ -81,8 +87,8 @@ public class IssueExclusionsRegexpScanner extends CharHandler { fileLength = lineIndex; if (!lineExclusions.isEmpty()) { Set lineRanges = convertLineExclusionsToLineRanges(); - LOG.debug("- Line exclusions found: {}", lineRanges); - patternMatcher.addPatternToExcludeLines(componentKey, lineRanges); + LOG.debug(" - Line exclusions found: {}", lineRanges.stream().map(LineRange::toString).collect(Collectors.joining(","))); + inputFile.addIgnoreIssuesOnLineRanges(lineRanges.stream().map(r -> new int[] {r.from(), r.to()}).collect(Collectors.toList())); } } @@ -94,9 +100,9 @@ public class IssueExclusionsRegexpScanner extends CharHandler { // 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); + LOG.debug(" - Exclusion pattern '{}': all issues in this file will be ignored.", pattern); + inputFile.setIgnoreAllIssues(true); return; } } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectReactorBuilder.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectReactorBuilder.java index 38d0d60733f..7dceaf350a0 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectReactorBuilder.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectReactorBuilder.java @@ -20,17 +20,18 @@ package org.sonar.scanner.scan; import com.google.common.annotations.VisibleForTesting; -import com.google.common.collect.Lists; import java.io.File; import java.nio.file.Path; import java.nio.file.Paths; import java.text.MessageFormat; import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.stream.Stream; import javax.annotation.CheckForNull; import javax.annotation.Nullable; import org.apache.commons.lang.ArrayUtils; @@ -38,16 +39,21 @@ import org.apache.commons.lang.StringUtils; import org.sonar.api.CoreProperties; import org.sonar.api.batch.bootstrap.ProjectDefinition; import org.sonar.api.batch.bootstrap.ProjectReactor; +import org.sonar.api.notifications.AnalysisWarnings; import org.sonar.api.utils.MessageException; import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Loggers; import org.sonar.api.utils.log.Profiler; +import org.sonar.core.config.IssueExclusionProperties; import org.sonar.scanner.bootstrap.ScannerProperties; +import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer; +import org.sonar.scanner.issue.ignore.pattern.IssueInclusionPatternInitializer; import org.sonar.scanner.util.ScannerUtils; +import static java.util.Arrays.asList; +import static java.util.stream.Collectors.toList; import static org.sonar.api.config.internal.MultivalueProperty.parseAsCsv; - /** * Class that creates a project definition based on a set of properties. */ @@ -95,17 +101,23 @@ public class ProjectReactorBuilder { */ private static final String[] MANDATORY_PROPERTIES_FOR_CHILD = {MODULE_KEY_PROPERTY}; + private static final Collection UNSUPPORTED_PROPS_FOR_MODULES = asList(IssueExclusionPatternInitializer.CONFIG_KEY, IssueInclusionPatternInitializer.CONFIG_KEY, + IssueExclusionProperties.PATTERNS_BLOCK_KEY, IssueExclusionProperties.PATTERNS_ALLFILE_KEY); + /** * Properties that must not be passed from the parent project to its children. */ - private static final List NON_HERITED_PROPERTIES_FOR_CHILD = Lists.newArrayList(PROPERTY_PROJECT_BASEDIR, CoreProperties.WORKING_DIRECTORY, PROPERTY_MODULES, - CoreProperties.PROJECT_DESCRIPTION_PROPERTY); + private static final List NON_HERITED_PROPERTIES_FOR_CHILD = Stream.concat(Stream.of(PROPERTY_PROJECT_BASEDIR, CoreProperties.WORKING_DIRECTORY, PROPERTY_MODULES, + CoreProperties.PROJECT_DESCRIPTION_PROPERTY), UNSUPPORTED_PROPS_FOR_MODULES.stream()).collect(toList()); private final ScannerProperties scannerProps; + private final AnalysisWarnings analysisWarnings; private File rootProjectWorkDir; + private boolean warnExclusionsAlreadyLogged; - public ProjectReactorBuilder(ScannerProperties props) { + public ProjectReactorBuilder(ScannerProperties props, AnalysisWarnings analysisWarnings) { this.scannerProps = props; + this.analysisWarnings = analysisWarnings; } public ProjectReactor execute() { @@ -121,7 +133,7 @@ public class ProjectReactorBuilder { } private static void extractPropertiesByModule(Map> propertiesByModuleIdPath, String currentModuleId, String currentModuleIdPath, - Map parentProperties) { + Map parentProperties) { if (propertiesByModuleIdPath.containsKey(currentModuleIdPath)) { throw MessageException.of(String.format("Two modules have the same id: '%s'. Each module must have a unique id.", currentModuleId)); } @@ -170,6 +182,7 @@ public class ProjectReactorBuilder { workDir = initRootProjectWorkDir(baseDir, moduleProperties); } else { workDir = initModuleWorkDir(baseDir, moduleProperties); + checkUnsupportedIssueExclusions(moduleProperties); } return ProjectDefinition.create().setProperties(moduleProperties) @@ -178,6 +191,23 @@ public class ProjectReactorBuilder { .setBuildDir(initModuleBuildDir(baseDir, moduleProperties)); } + private void checkUnsupportedIssueExclusions(Map moduleProperties) { + UNSUPPORTED_PROPS_FOR_MODULES.stream().forEach(p -> { + if (moduleProperties.containsKey(p)) { + warnOnceUnsupportedIssueExclusions( + "Specifying issue exclusions at module level is not supported anymore. Configure the property '" + p + "' and any other issue exclusions at project level."); + } + }); + } + + private void warnOnceUnsupportedIssueExclusions(String msg) { + if (!warnExclusionsAlreadyLogged) { + LOG.warn(msg); + analysisWarnings.addUnique(msg); + warnExclusionsAlreadyLogged = true; + } + } + @VisibleForTesting protected File initRootProjectWorkDir(File baseDir, Map rootProperties) { String workDir = rootProperties.get(CoreProperties.WORKING_DIRECTORY); diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java index b3d656a55c3..6171c2793de 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java @@ -47,7 +47,6 @@ import org.sonar.scanner.bootstrap.MetricProvider; import org.sonar.scanner.bootstrap.PostJobExtensionDictionnary; import org.sonar.scanner.cpd.CpdExecutor; import org.sonar.scanner.cpd.CpdSettings; -import org.sonar.scanner.cpd.JavaCpdBlockIndexerSensor; import org.sonar.scanner.cpd.index.SonarCpdBlockIndex; import org.sonar.scanner.deprecated.test.TestPlanBuilder; import org.sonar.scanner.deprecated.test.TestableBuilder; @@ -59,7 +58,6 @@ 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.tracking.DefaultServerLineHashesLoader; import org.sonar.scanner.issue.tracking.IssueTransition; @@ -230,7 +228,6 @@ public class ProjectScanContainer extends ComponentContainer { // issue exclusions IssueInclusionPatternInitializer.class, IssueExclusionPatternInitializer.class, - PatternMatcher.class, IssueExclusionsLoader.class, EnforceIssuesFilter.class, IgnoreIssuesFilter.class, diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/FileIndexer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/FileIndexer.java index cd9767328a2..aba73c172a4 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/FileIndexer.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/FileIndexer.java @@ -134,9 +134,7 @@ public class FileIndexer { } checkIfAlreadyIndexed(inputFile); componentStore.put(module.key(), inputFile); - if (issueExclusionsLoader.shouldExecute()) { - issueExclusionsLoader.addMulticriteriaPatterns(inputFile.getProjectRelativePath(), inputFile.key()); - } + issueExclusionsLoader.addMulticriteriaPatterns(inputFile); LOG.debug("'{}' indexed {}with language '{}'", projectRelativePath, type == Type.TEST ? "as test " : "", inputFile.language()); evaluateCoverageExclusions(moduleCoverageExclusions, inputFile); if (properties.preloadFileMetadata()) { diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/MetadataGenerator.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/MetadataGenerator.java index a603edbe6de..cf7833e18fc 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/MetadataGenerator.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/MetadataGenerator.java @@ -64,7 +64,7 @@ public class MetadataGenerator { } InputStream is = charsetDetector.inputStream(); inputFile.setCharset(charset); - Metadata metadata = fileMetadata.readMetadata(is, charset, inputFile.absolutePath(), exclusionsScanner.createCharHandlerFor(inputFile.key())); + Metadata metadata = fileMetadata.readMetadata(is, charset, inputFile.absolutePath(), exclusionsScanner.createCharHandlerFor(inputFile)); inputFile.setMetadata(metadata); inputFile.setStatus(statusDetection.status(moduleKeyWithBranch, inputFile, metadata.hash())); LOG.debug("'{}' generated metadata{} with charset '{}'", inputFile, inputFile.type() == Type.TEST ? " as test " : "", charset); -- cgit v1.2.3