SonarQube Java规则问询:未被继承的类需设为final的实现
优化你的SonarQube「未继承类设为final」规则实现
看起来你已经迈出了规则开发的第一步,但当前的实现还有几个关键问题需要修正,才能准确完成规则的预期功能。我来帮你梳理下问题点并给出改进方案:
现有代码的核心问题
symbol().usages()无法精准判断继承关系:这个方法返回的是类符号的所有引用(比如创建实例、调用静态方法等),但不能直接区分哪些是继承操作,所以单纯统计数量完全无法判断类是否被继承。- 缺少必要的过滤逻辑:你没有排除接口、抽象类,也没检查类本身是否已经是
final——这些场景下规则都不应该触发。 - 没有违规报告逻辑:当前代码只是打印引用数量,并没有向SonarQube平台提交违规问题,这样规则根本无法生效。
改进后的完整实现
import org.sonar.plugins.java.api.tree.ClassTree; import org.sonar.plugins.java.api.tree.Tree; import org.sonar.plugins.java.api.tree.Modifier; import org.sonar.plugins.java.api.JavaFileScanner; import org.sonar.plugins.java.api.JavaFileScannerContext; import com.google.common.collect.ImmutableList; public class FinalUninheritedClassRule implements JavaFileScanner { private JavaFileScannerContext context; @Override public void scanFile(JavaFileScannerContext context) { this.context = context; } @Override public List<Tree.Kind> nodesToVisit() { return ImmutableList.of(Tree.Kind.CLASS); } @Override public void visitNode(Tree tree) { ClassTree classTree = (ClassTree) tree; // 跳过不需要检查的类:接口、抽象类、已为final的类 if (classTree.isInterface() || classTree.modifiers().hasModifier(Modifier.ABSTRACT) || classTree.modifiers().hasModifier(Modifier.FINAL)) { return; } // 精准判断当前类是否被其他类继承 boolean isClassInherited = classTree.symbol().usages().stream() .anyMatch(usage -> { // 检查引用的父节点是否是类定义,且该类的extends子句指向当前类 if (usage.parent() instanceof ClassTree) { ClassTree parentClass = (ClassTree) usage.parent(); return parentClass.extendsClause() != null && parentClass.extendsClause().symbol().equals(classTree.symbol()); } return false; }); // 如果未被继承,向SonarQube报告违规 if (!isClassInherited) { context.reportIssue(this, classTree.simpleName(), "未被继承的非抽象类应该声明为final"); } } }
关键优化点说明
- 精准识别继承关系:通过遍历引用,检查每个引用的父节点是否是类定义,且该类的
extendsClause符号与当前类符号一致,这样就能准确判断当前类是否被继承。 - 完善过滤逻辑:自动排除接口、抽象类和已标记为final的类,避免无效的误报。
- 添加违规报告:通过
context.reportIssue()方法向SonarQube提交问题,这是规则能在平台上显示的核心步骤。
测试代码建议
测试时要覆盖所有场景,确保规则能正确触发或忽略:
// 应该触发违规:未被继承且非final public class UninheritedClass { } // 不触发违规:被其他类继承 public class BaseClass { } public class SubClass extends BaseClass { } // 不触发违规:已为final类 public final class FinalClass { } // 不触发违规:抽象类 public abstract class AbstractBaseClass { }
内容的提问来源于stack exchange,提问作者Carlos Cobos




