How to create a Lint check to ensure an Activity/Fragment is attached?












0















I am trying to create a custom Lint check so that particular annotated methods have to first ensure that the fragment/activity is attached/visible before doing any work.



E.g.



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
}
}

}


To do this, I have created an IssueRegistry, the @CheckIsActive annotation and the following custom Detector class.



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);

}
}
};
}
}


I have struggled to work out how to progress from the state I am in now, which is (I believe) entering a method and correctly checking if it was annotated. I am not sure with the detector methods, how to




  1. Check if the containing class extends Activity / Fragment

  2. Check if isAdded() for Fragment or isDestroyed() for Activity was called


Does anyone have any idea how to carry on from this or know where any of this is documented? It seems Google is not using the latest lint version within their source (e.g. CallSuper source) so that has not been too much help.



Thanks










share|improve this question

























  • A beginner dev here. Not sure what you are doing but I simply use Fragment fragment = new MyFragment(); if(fragment.getActivity()!=null) { // attached} else{ //not attached }

    – Pemba Tamang
    Dec 3 '18 at 9:25











  • Hi @PembaTamang, thanks for your comment but that is not really what I am asking. I want to create a custom Lint check to ensure the code you provided is present in a method

    – Ed George
    Dec 14 '18 at 11:31
















0















I am trying to create a custom Lint check so that particular annotated methods have to first ensure that the fragment/activity is attached/visible before doing any work.



E.g.



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
}
}

}


To do this, I have created an IssueRegistry, the @CheckIsActive annotation and the following custom Detector class.



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);

}
}
};
}
}


I have struggled to work out how to progress from the state I am in now, which is (I believe) entering a method and correctly checking if it was annotated. I am not sure with the detector methods, how to




  1. Check if the containing class extends Activity / Fragment

  2. Check if isAdded() for Fragment or isDestroyed() for Activity was called


Does anyone have any idea how to carry on from this or know where any of this is documented? It seems Google is not using the latest lint version within their source (e.g. CallSuper source) so that has not been too much help.



Thanks










share|improve this question

























  • A beginner dev here. Not sure what you are doing but I simply use Fragment fragment = new MyFragment(); if(fragment.getActivity()!=null) { // attached} else{ //not attached }

    – Pemba Tamang
    Dec 3 '18 at 9:25











  • Hi @PembaTamang, thanks for your comment but that is not really what I am asking. I want to create a custom Lint check to ensure the code you provided is present in a method

    – Ed George
    Dec 14 '18 at 11:31














0












0








0


0






I am trying to create a custom Lint check so that particular annotated methods have to first ensure that the fragment/activity is attached/visible before doing any work.



E.g.



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
}
}

}


To do this, I have created an IssueRegistry, the @CheckIsActive annotation and the following custom Detector class.



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);

}
}
};
}
}


I have struggled to work out how to progress from the state I am in now, which is (I believe) entering a method and correctly checking if it was annotated. I am not sure with the detector methods, how to




  1. Check if the containing class extends Activity / Fragment

  2. Check if isAdded() for Fragment or isDestroyed() for Activity was called


Does anyone have any idea how to carry on from this or know where any of this is documented? It seems Google is not using the latest lint version within their source (e.g. CallSuper source) so that has not been too much help.



Thanks










share|improve this question
















I am trying to create a custom Lint check so that particular annotated methods have to first ensure that the fragment/activity is attached/visible before doing any work.



E.g.



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
}
}

}


To do this, I have created an IssueRegistry, the @CheckIsActive annotation and the following custom Detector class.



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);

}
}
};
}
}


I have struggled to work out how to progress from the state I am in now, which is (I believe) entering a method and correctly checking if it was annotated. I am not sure with the detector methods, how to




  1. Check if the containing class extends Activity / Fragment

  2. Check if isAdded() for Fragment or isDestroyed() for Activity was called


Does anyone have any idea how to carry on from this or know where any of this is documented? It seems Google is not using the latest lint version within their source (e.g. CallSuper source) so that has not been too much help.



Thanks







android lint






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 24 '18 at 15:49







Ed George

















asked Nov 24 '18 at 15:44









Ed GeorgeEd George

4,12212754




4,12212754













  • A beginner dev here. Not sure what you are doing but I simply use Fragment fragment = new MyFragment(); if(fragment.getActivity()!=null) { // attached} else{ //not attached }

    – Pemba Tamang
    Dec 3 '18 at 9:25











  • Hi @PembaTamang, thanks for your comment but that is not really what I am asking. I want to create a custom Lint check to ensure the code you provided is present in a method

    – Ed George
    Dec 14 '18 at 11:31



















  • A beginner dev here. Not sure what you are doing but I simply use Fragment fragment = new MyFragment(); if(fragment.getActivity()!=null) { // attached} else{ //not attached }

    – Pemba Tamang
    Dec 3 '18 at 9:25











  • Hi @PembaTamang, thanks for your comment but that is not really what I am asking. I want to create a custom Lint check to ensure the code you provided is present in a method

    – Ed George
    Dec 14 '18 at 11:31

















A beginner dev here. Not sure what you are doing but I simply use Fragment fragment = new MyFragment(); if(fragment.getActivity()!=null) { // attached} else{ //not attached }

– Pemba Tamang
Dec 3 '18 at 9:25





A beginner dev here. Not sure what you are doing but I simply use Fragment fragment = new MyFragment(); if(fragment.getActivity()!=null) { // attached} else{ //not attached }

– Pemba Tamang
Dec 3 '18 at 9:25













Hi @PembaTamang, thanks for your comment but that is not really what I am asking. I want to create a custom Lint check to ensure the code you provided is present in a method

– Ed George
Dec 14 '18 at 11:31





Hi @PembaTamang, thanks for your comment but that is not really what I am asking. I want to create a custom Lint check to ensure the code you provided is present in a method

– Ed George
Dec 14 '18 at 11:31












1 Answer
1






active

oldest

votes


















0














I suspect the actual Lint rule will be very complicated, but in very simple case it can be implemented this way:



@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
}
}





share|improve this answer

























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53459774%2fhow-to-create-a-lint-check-to-ensure-an-activity-fragment-is-attached%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    0














    I suspect the actual Lint rule will be very complicated, but in very simple case it can be implemented this way:



    @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
    }
    }





    share|improve this answer






























      0














      I suspect the actual Lint rule will be very complicated, but in very simple case it can be implemented this way:



      @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
      }
      }





      share|improve this answer




























        0












        0








        0







        I suspect the actual Lint rule will be very complicated, but in very simple case it can be implemented this way:



        @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
        }
        }





        share|improve this answer















        I suspect the actual Lint rule will be very complicated, but in very simple case it can be implemented this way:



        @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
        }
        }






        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Dec 27 '18 at 13:57

























        answered Dec 27 '18 at 13:44









        italankinitalankin

        716




        716






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53459774%2fhow-to-create-a-lint-check-to-ensure-an-activity-fragment-is-attached%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Futebolista

            Lallio

            Jornalista