You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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

火山引擎 最新活动