/*
* SonarQube Java
* Copyright (C) 2012-2016 SonarSource SA
* mailto:contact 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.java.filters;
import com.google.common.collect.ContiguousSet;
import com.google.common.collect.DiscreteDomain;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Range;
import org.sonar.api.scan.issue.filter.FilterableIssue;
import org.sonar.api.utils.AnnotationUtils;
import org.sonar.check.Rule;
import org.sonar.plugins.java.api.JavaCheck;
import org.sonar.plugins.java.api.JavaFileScannerContext;
import org.sonar.plugins.java.api.tree.BaseTreeVisitor;
import org.sonar.plugins.java.api.tree.SyntaxToken;
import org.sonar.plugins.java.api.tree.Tree;
import javax.annotation.Nullable;
import java.util.Map;
import java.util.Set;
public abstract class BaseTreeVisitorIssueFilter extends BaseTreeVisitor implements JavaIssueFilter {
private String componentKey;
private final Multimap<String, Integer> excludedLinesByRule;
private final Map<Class<? extends JavaCheck>, String> rulesKeysByRulesClass;
public BaseTreeVisitorIssueFilter() {
excludedLinesByRule = HashMultimap.create();
rulesKeysByRulesClass = rulesKeysByRulesClass(filteredRules());
}
private static Map<Class<? extends JavaCheck>, String> rulesKeysByRulesClass(Set<Class<? extends JavaCheck>> rules) {
Map<Class<? extends JavaCheck>, String> results = Maps.newHashMap();
for (Class<? extends JavaCheck> ruleClass : rules) {
Rule ruleAnnotation = AnnotationUtils.getAnnotation(ruleClass, Rule.class);
if (ruleAnnotation != null) {
results.put(ruleClass, ruleAnnotation.key());
}
}
return results;
}
@Override
public void setComponentKey(String componentKey) {
this.componentKey = componentKey;
}
public String getComponentKey() {
return componentKey;
}
@Override
public void scanFile(JavaFileScannerContext context) {
excludedLinesByRule.clear();
scan(context.getTree());
}
@Override
public boolean accept(FilterableIssue issue) {
return !(issue.componentKey().equals(componentKey) && excludedLinesByRule.get(issue.ruleKey().rule()).contains(issue.line()));
}
public Multimap<String, Integer> excludedLinesByRule() {
return excludedLinesByRule;
}
public void acceptLines(@Nullable Tree tree, Iterable<Class<? extends JavaCheck>> rules) {
for (Class<? extends JavaCheck> rule : rules) {
acceptLines(tree, rule);
}
}
public void acceptLines(@Nullable Tree tree, Class<? extends JavaCheck> rule) {
computeFilteredLinesForRule(tree, rule, false);
}
public void excludeLines(@Nullable Tree tree, Iterable<Class<? extends JavaCheck>> rules) {
for (Class<? extends JavaCheck> rule : rules) {
excludeLines(tree, rule);
}
}
public void excludeLines(Set<Integer> lines, String ruleKey) {
computeFilteredLinesForRule(lines, ruleKey, true);
}
public void excludeLines(@Nullable Tree tree, Class<? extends JavaCheck> rule) {
computeFilteredLinesForRule(tree, rule, true);
}
private void computeFilteredLinesForRule(@Nullable Tree tree, Class<? extends JavaCheck> filteredRule, boolean excludeLine) {
if (tree == null) {
return;
}
SyntaxToken firstSyntaxToken = tree.firstToken();
SyntaxToken lastSyntaxToken = tree.lastToken();
if (firstSyntaxToken != null && lastSyntaxToken != null) {
Set<Integer> filteredlines = ContiguousSet.create(Range.closed(firstSyntaxToken.line(), lastSyntaxToken.line()), DiscreteDomain.integers());
computeFilteredLinesForRule(filteredlines, rulesKeysByRulesClass.get(filteredRule), excludeLine);
}
}
private void computeFilteredLinesForRule(Set<Integer> lines, String ruleKey, boolean excludeLine) {
if (excludeLine) {
excludedLinesByRule.putAll(ruleKey, lines);
} else {
excludedLinesByRule.get(ruleKey).removeAll(lines);
}
}
}