-
Notifications
You must be signed in to change notification settings - Fork 29
Add test for @SuppressWarnings and @AnnotatedFor interaction and refine SourceChecker logic
#1699
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
2a48175
66e664f
90c6889
87b149f
19dfafc
ca073e6
569903b
f63127a
da31816
f11ee59
2d93fb8
8e85969
2844c1c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -694,8 +694,11 @@ | |
|
|
||
| \sectionAndLabel{\code{-AonlyAnnotatedFor} command-line option}{aonlyannotatedfor} | ||
|
|
||
| You can suppress all errors and warnings for code outside of a corresponding \code{@AnnotatedFor} by applying this command-line option. | ||
| Note that the \code{@AnnotatedFor} annotation must include the checker's name to enable warnings from that checker. | ||
| You can suppress all errors and warnings for code outside of a corresponding | ||
| \code{@AnnotatedFor} by applying this command-line option. | ||
| Note that the \code{@AnnotatedFor} annotation must include the checker's name to | ||
| enable warnings from that checker, except for warnings suppressed by another | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are the "Note" and "except" part really connected? Maybe make the "except" part a separate sentence that highlights that explicit SuppressWarnings suppress warnings in AnnotatedFor code and in UnannotatedFor code (if the extra flag is not there). |
||
| mechanism such as \code{@SuppressWarnings}. | ||
| For example, use \code{@AnnotatedFor("nullness")} for the Nullness Checker. | ||
| This flag only suppresses warnings, compared to \code{-AuseConservativeDefaultsForUncheckedCode=source}, | ||
| which also applies conservative defaults for code outside the scope of an \code{@AnnotatedFor} annotation. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2773,6 +2773,12 @@ public boolean shouldSuppressWarnings(Tree tree, String errKey) { | |
| * otherwise | ||
| */ | ||
| public boolean shouldSuppressWarnings(TreePath path, String errKey) { | ||
| if (shouldSuppress(getSuppressWarningsStringsFromOption(), errKey)) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Should both checks from the Tree version be moved to the TreePath version? Are there other places that call this method that should not have both checks? |
||
| return true; | ||
| } | ||
|
|
||
| boolean foundAnnotatedFor = false; | ||
|
|
||
| // iterate through the path; continue until path contains no declarations | ||
| for (TreePath declPath = TreePathUtil.enclosingDeclarationPath(path); | ||
| declPath != null; | ||
|
|
@@ -2781,49 +2787,46 @@ public boolean shouldSuppressWarnings(TreePath path, String errKey) { | |
|
|
||
| if (decl instanceof VariableTree) { | ||
| Element elt = TreeUtils.elementFromDeclaration((VariableTree) decl); | ||
| if (shouldSuppressWarnings(elt, errKey)) { | ||
| if (shouldSuppressWarningsOnElement(elt, errKey)) { | ||
| return true; | ||
| } | ||
| } else if (decl instanceof MethodTree) { | ||
| Element elt = TreeUtils.elementFromDeclaration((MethodTree) decl); | ||
| if (shouldSuppressWarnings(elt, errKey)) { | ||
| if (shouldSuppressWarningsOnElement(elt, errKey)) { | ||
| return true; | ||
| } | ||
|
|
||
| if (isAnnotatedForThisCheckerOrUpstreamChecker(elt)) { | ||
| // Return false immediately. Do NOT check for AnnotatedFor in the enclosing | ||
| // elements as the closest AnnotatedFor is already found. | ||
| return false; | ||
| if (!foundAnnotatedFor && isAnnotatedForThisCheckerOrUpstreamChecker(elt)) { | ||
| foundAnnotatedFor = true; | ||
| } | ||
| } else if (TreeUtils.classTreeKinds().contains(decl.getKind())) { | ||
| // A class tree | ||
| Element elt = TreeUtils.elementFromDeclaration((ClassTree) decl); | ||
| if (shouldSuppressWarnings(elt, errKey)) { | ||
| if (shouldSuppressWarningsOnElement(elt, errKey)) { | ||
| return true; | ||
| } | ||
|
|
||
| if (isAnnotatedForThisCheckerOrUpstreamChecker(elt)) { | ||
| // Return false immediately. Do NOT check for AnnotatedFor in the enclosing | ||
| // elements as the closest AnnotatedFor is already found. | ||
| return false; | ||
| if (!foundAnnotatedFor && isAnnotatedForThisCheckerOrUpstreamChecker(elt)) { | ||
| foundAnnotatedFor = true; | ||
| } | ||
| Element packageElement = elt.getEnclosingElement(); | ||
| if (packageElement != null && packageElement.getKind() == ElementKind.PACKAGE) { | ||
| if (shouldSuppressWarnings(packageElement, errKey)) { | ||
| if (shouldSuppressWarningsOnElement(packageElement, errKey)) { | ||
| return true; | ||
| } | ||
| if (isAnnotatedForThisCheckerOrUpstreamChecker(packageElement)) { | ||
| // Return false immediately. Do NOT check for AnnotatedFor in the enclosing | ||
| // elements as the closest AnnotatedFor is already found. | ||
| return false; | ||
| if (!foundAnnotatedFor | ||
| && isAnnotatedForThisCheckerOrUpstreamChecker(packageElement)) { | ||
| foundAnnotatedFor = true; | ||
| } | ||
| } | ||
| } else { | ||
| throw new BugInCF("Unexpected declaration kind: " + decl.getKind() + " " + decl); | ||
| } | ||
| } | ||
|
|
||
| if (useConservativeDefaultsSource || onlyAnnotatedFor) { | ||
| if (foundAnnotatedFor) { | ||
| return false; | ||
| } else if (useConservativeDefaultsSource || onlyAnnotatedFor) { | ||
| // If we got this far without hitting an @AnnotatedFor and returning | ||
| // false, we DO suppress the warning. | ||
| return true; | ||
|
|
@@ -2882,20 +2885,30 @@ public boolean shouldSuppressWarnings(Element elt, String errKey) { | |
| } | ||
|
|
||
| for (Element currElt = elt; currElt != null; currElt = currElt.getEnclosingElement()) { | ||
| SuppressWarnings suppressWarningsAnno = currElt.getAnnotation(SuppressWarnings.class); | ||
| if (suppressWarningsAnno != null) { | ||
| String[] suppressWarningsStrings = suppressWarningsAnno.value(); | ||
| if (shouldSuppress(suppressWarningsStrings, errKey)) { | ||
| if (warnUnneededSuppressions) { | ||
| elementsWithSuppressedWarnings.add(currElt); | ||
| } | ||
| return true; | ||
| } | ||
| if (shouldSuppressWarningsOnElement(currElt, errKey)) { | ||
| return true; | ||
| } | ||
| if (isAnnotatedForThisCheckerOrUpstreamChecker(elt)) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The I would expect that we need to find two things:
Once we found an AnnotatedFor or UnannotatedFor, we can stop looking for the other as well, but we do need to continue looking for a SuppressWarnings, and the other way around. Can you look through the other overload and write a test case that triggers that version?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Updated. The
The new logic does that by tracking whether an applicable
I updated the relevant manual sections to state that diagnostics in an |
||
| // Return false immediately. Do NOT check for AnnotatedFor in the | ||
| // enclosing elements, because they may not have an @AnnotatedFor. | ||
| return false; | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
| /** | ||
| * Returns true if the given element has a {@code @SuppressWarnings} annotation that suppresses | ||
| * the given error key. | ||
| * | ||
| * @param elt the element whose annotations to check | ||
| * @param errKey the error key the checker is emitting | ||
| * @return true if {@code elt} has an corresponding {@code @SuppressWarnings} annotation | ||
| */ | ||
| private boolean shouldSuppressWarningsOnElement(Element elt, String errKey) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There already is a |
||
| SuppressWarnings suppressWarningsAnno = elt.getAnnotation(SuppressWarnings.class); | ||
| if (suppressWarningsAnno != null) { | ||
| String[] suppressWarningsStrings = suppressWarningsAnno.value(); | ||
| if (shouldSuppress(suppressWarningsStrings, errKey)) { | ||
| if (warnUnneededSuppressions) { | ||
| elementsWithSuppressedWarnings.add(elt); | ||
| } | ||
| return true; | ||
| } | ||
| } | ||
| return false; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sentence comes out of the blue and the connection to what's in the paragraph before is unclear. What is "still" referring to?
Would it make more sense to first keep the existing text and then say the new part? Is the "still" referring to passing
-AonlyAnnotatedFor? Is that the important point?