如何创建Lint检查以确保附加了活动/片段?

时间:2018-11-24 15:44:17

标签: android lint

我正在尝试创建自定义的Lint检查,以便特殊的注释方法必须先确保片段/活动已附加/可见,然后再进行任何工作。

例如

class MyFragment extends Fragment {

    @CheckIsActive
    void lint_fail() {
        // This would throw a lint warning
    }

    @CheckIsActive
    void lint_succeed() {
        if(isAdded()) {
            // This wouldn't throw a lint warning
        }
    }

}

为此,我创建了一个IssueRegistry@CheckIsActive批注和以下自定义Detector类。

public class CheckActiveDetector extends Detector implements Detector.UastScanner {

    private static final String CHECK_ACTIVE_ANNOTATION = Constants.ANNOTATIONS_PREFIX + "CheckIsActive";

    private static final Implementation IMPLEMENTATION = new Implementation(
            CheckActiveDetector.class,
            Scope.JAVA_FILE_SCOPE);

    public static final Issue ISSUE = Issue.create(
            "CheckActive",
            "Method should check if the activity/fragment is active",
            "This method should ensure the Activity/Fragment is active before continuing",
            Category.CORRECTNESS,
            9,
            Severity.WARNING,
            IMPLEMENTATION
    );


    public CheckActiveDetector() {}

    @Nullable
    @Override
    public List<Class<? extends UElement>> getApplicableUastTypes() {
        return Collections.<Class<? extends UElement>>singletonList(UMethod.class);
    }

    @Nullable
    @Override
    public UElementHandler createUastHandler(@NotNull final JavaContext context) {
        return new UElementHandler() {
            @Override
            public void visitMethod(@NotNull UMethod node) {


                UExpression body = node.getUastBody();
                if(body != null && node.findAnnotation(CHECK_ACTIVE_ANNOTATION) != null) {

                    String methodName = node.getName();
                    String message = "Overriding method should call `isAdded()"
                            + methodName + "`";
                    Location location = context.getLocation(node);
                    context.report(ISSUE, node, location, message);

                }
            }
        };
    }
}

我一直在努力寻找如何从我现在所处的状态前进,我认为这是进入一种方法并正确检查它是否被注释的状态。我不确定探测器的方法,如何

  1. 检查包含的类是否扩展了Activity / Fragment
  2. 检查是否为片段调用了isAdded()或为Activity调用了isDestroyed()

有人知道如何进行此操作或知道其中的任何记录吗?看来Google并未在其来源中使用最新的lint版本(例如CallSuper source),因此并没有太大帮助。

谢谢

1 个答案:

答案 0 :(得分:0)

我怀疑实际的Lint规则会非常复杂,但是在非常简单的情况下,可以通过以下方式实现:

@Override
public void visitMethod(@NotNull UMethod node) {
    if (node.findAnnotation(CHECK_ACTIVE_ANNOTATION) == null) {
        return;
    }
    UExpression body = node.getUastBody();
    if (!(body instanceof UBlockExpression)) {
        return;
    }
    List<UExpression> expressions = ((UBlockExpression) body).getExpressions();
    UExpression firstExpression = expressions.get(0);
    // check if the first expression in method body is 'if' expression
    if (!(firstExpression instanceof UIfExpression)) {
        // probably it is not okay
        return;
    }
    UExpression condition = ((UIfExpression) firstExpression).getCondition();
    if (!(condition instanceof UCallExpression)) {
        // isAdded() is a method call, so we need a UCallExpression
        // probably not ok
        return;
    }
    if ("isAdded".equals(((UCallExpression) condition).getMethodName())) {
        // it is ok

        // you can also check argument count and the owner of the method to
        // ensure it is the correct one
    } else {
        // it is not ok
    }
}