Java 限制SonarQube中每行相同检查的问题
我正在使用Java插件API为SonarQube 5.6.6开发一个插件。我创建了一些自定义规则(检查),其中一个在同一行中多次报告相同的问题。这是有意义的,因为该行多次出现相同的错误,但是,有没有办法限制这一点,以便SonarQube只显示该行中的问题 图像(和代码)胜于雄辩,因此我将展示一个示例:一个检查,它在每次检测到新类时都报告一个问题Java 限制SonarQube中每行相同检查的问题,java,plugins,sonarqube,Java,Plugins,Sonarqube,我正在使用Java插件API为SonarQube 5.6.6开发一个插件。我创建了一些自定义规则(检查),其中一个在同一行中多次报告相同的问题。这是有意义的,因为该行多次出现相同的错误,但是,有没有办法限制这一点,以便SonarQube只显示该行中的问题 图像(和代码)胜于雄辩,因此我将展示一个示例:一个检查,它在每次检测到新类时都报告一个问题 @Rule(key = "foo_key", name = "Foo issue", description = "Foo issue", priori
@Rule(key = "foo_key", name = "Foo issue", description = "Foo issue", priority = Priority.INFO)
public class FooCheck extends IssuableSubscriptionVisitor {
@Override
public List<Kind> nodesToVisit() {
return ImmutableList.of(Kind.NEW_CLASS);
}
@Override
public void visitNode(Tree tree) {
reportIssue(tree, "New class!");
}
}
然而,这是一个解决方案,仅此检查。我想知道是否有一个通用的方法告诉SonarQube不要在每行显示相同检查的几个问题
谢谢。您可以在报告问题之前获取
树
节点的行号,将其保存到全局变量lastLineReported
或报告行列表中。然后,用一个简单的if
语句以两种方式进行检查:
1-使用lastLineReported变量:
if(lastLineReported != currentLine) {
lastLineReported = currentLine;
reportIssue(tree, "New class!");
}
if(!reportedLines.contains(currentLine)) {
reportedLines.add(currentLine);
reportIssue(tree, "New class!");
}
2-使用报告的行列表:
if(lastLineReported != currentLine) {
lastLineReported = currentLine;
reportIssue(tree, "New class!");
}
if(!reportedLines.contains(currentLine)) {
reportedLines.add(currentLine);
reportIssue(tree, "New class!");
}
基于此,我将提供完整的解决方案:
关键是接口Tree
(org.sonar.plugins.java.api.Tree.Tree
)有一个方法firstToken()
,它返回一个SyntaxToken
,这是另一个接口,它有一个方法行()。因此,我们可以调用tree.firstToken().line()
来获取我们正在访问的节点的行,在我们第一次报告该行上的问题时保存它,并在以后访问节点时检查它们的行是否已经报告了问题
注意:我们不能在集合中静态保存这些行,因为每次访问要分析的每个源代码文件的节点时,都会共享该集合的值。相反,我们必须将每一行与正在分析的文件一起保存。如果我们没有这样做,并且在文件a的X行中创建了一个问题,如果文件B在其X行中有问题,则不会创建此问题
@Rule(key = "foo_key", name = "Foo issue", description = "Foo issue", priority = Priority.INFO)
public class FooCheck extends IssuableSubscriptionVisitor {
private static final Map<String, Collection<Integer>> linesWithIssuesByClass = new HashMap<>();
@Override
public List<Kind> nodesToVisit() {
return ImmutableList.of(Kind.NEW_CLASS);
}
@Override
public void visitNode(Tree tree) {
if (lineAlreadyHasThisIssue(tree)) {
return;
}
reportIssue(tree);
}
private boolean lineAlreadyHasThisIssue(Tree tree) {
if (tree.firstToken() != null) {
final String classname = getFullyQualifiedNameOfClassOf(tree);
final int line = tree.firstToken().line();
return linesWithIssuesByClass.containsKey(classname)
&& linesWithIssuesByClass.get(classname).contains(line);
}
return false;
}
private void reportIssue(Tree tree) {
if (tree.firstToken() != null) {
final String classname = getFullyQualifiedNameOfClassOf(tree);
final int line = tree.firstToken().line();
if (!linesWithIssuesByClass.containsKey(classname)) {
linesWithIssuesByClass.put(classname, new ArrayList<>());
}
linesWithIssuesByClass.get(classname).add(line);
}
reportIssue(tree, "New class!");
}
private String getFullyQualifiedNameOfClassOf(Tree tree) {
Tree parent = tree.parent();
while (parent != null) {
final Tree grandparent = parent.parent();
if (parent.is(Kind.CLASS) && grandparent != null && grandparent.is(Kind.COMPILATION_UNIT)) {
final String packageName = getPackageName((CompilationUnitTree) grandparent);
return packageName.isEmpty()
? getClassName((ClassTree) parent)
: packageName + '.' + getClassName((ClassTree) parent);
}
parent = parent.parent();
}
return "";
}
private String getPackageName(CompilationUnitTree compilationUnitTree) {
final PackageDeclarationTree packageDeclarationTree = compilationUnitTree.packageDeclaration();
if (packageDeclarationTree == null) {
return "";
}
return packageDeclarationTree.packageName().toString();
}
private String getClassName(ClassTree classTree) {
final IdentifierTree simpleName = classTree.simpleName();
return simpleName == null
? ""
: simpleName.toString();
}
}
虽然Tree
有另一个方法lastToken()
返回另一个带有行的SyntaxToken
,但我们应该调用firstToken()
,因为我们的节点可能是这样的多行:
Foo foo = new Foo(
new Bar()
);
而lastToken().line()
在每次访问节点时都会有不同的值,而firstToken().line()
不会。多亏了你的回答,我可以解决我的问题,所以我投了更高的票。:)为了完整起见,我编写了另一个答案来指定与SonarQube接口相关的代码。