How to create a Lint check to ensure an Activity/Fragment is attached?
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
- Check if the containing class extends Activity / Fragment
- Check if
isAdded()for Fragment orisDestroyed()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
add a comment |
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
- Check if the containing class extends Activity / Fragment
- Check if
isAdded()for Fragment orisDestroyed()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
A beginner dev here. Not sure what you are doing but I simply useFragment 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
add a comment |
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
- Check if the containing class extends Activity / Fragment
- Check if
isAdded()for Fragment orisDestroyed()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
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
- Check if the containing class extends Activity / Fragment
- Check if
isAdded()for Fragment orisDestroyed()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
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 useFragment 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
add a comment |
A beginner dev here. Not sure what you are doing but I simply useFragment 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
add a comment |
1 Answer
1
active
oldest
votes
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
}
}
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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
}
}
add a comment |
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
}
}
add a comment |
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
}
}
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
}
}
edited Dec 27 '18 at 13:57
answered Dec 27 '18 at 13:44
italankinitalankin
716
716
add a comment |
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
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