@Override public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute) { if (context.getDriver().isSuppressed(context, ISSUE, attribute)) { mIgnoreFile = true; return; } if (mFileAttributes == null) { mFileAttributes = new ArrayList<>(); } mFileAttributes.add(attribute); }
@Override public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute) { if (context.getDriver().isSuppressed(context, ISSUE, attribute)) { mIgnoreFile = true; return; } if (mFileAttributes == null) { mFileAttributes = new ArrayList<Attr>(); } mFileAttributes.add(attribute); }
/** * Returns whether the given issue is suppressed for the given field. * * @param issue the issue to be checked, or null to just check for "all" * @param field the field potentially annotated with a suppress annotation * @return true if there is a suppress annotation covering the specific * issue on this field */ @SuppressWarnings("MethodMayBeStatic") // API; reserve need to require driver state later public boolean isSuppressed(@Nullable Issue issue, @NonNull FieldNode field) { if (field.invisibleAnnotations != null) { @SuppressWarnings("unchecked") List<AnnotationNode> annotations = field.invisibleAnnotations; return isSuppressed(issue, annotations); } return false; }
@Override public boolean visitSelect(Select node) { String description = node.astIdentifier().astValue(); boolean isIfRoom = description.equals("SHOW_AS_ACTION_IF_ROOM"); //$NON-NLS-1$ boolean isAlways = description.equals("SHOW_AS_ACTION_ALWAYS"); //$NON-NLS-1$ if ((isIfRoom || isAlways) && node.astOperand().toString().equals("MenuItem")) { //$NON-NLS-1$ if (isAlways) { if (mContext.getDriver().isSuppressed(mContext, ISSUE, node)) { return super.visitSelect(node); } if (mAlwaysFields == null) { mAlwaysFields = new ArrayList<Location>(); } mAlwaysFields.add(mContext.getLocation(node)); } else { mHasIfRoomRefs = true; } } return super.visitSelect(node); } }
private static void report(Context context, Issue issue, Handle handle, String message) { Location location = handle.resolve(); Object clientData = handle.getClientData(); if (clientData instanceof Node) { if (context.getDriver().isSuppressed(null, issue, (Node) clientData)) { return; } } context.report(issue, location, message); }
private static void report(Context context, Issue issue, Handle handle, String message) { Location location = handle.resolve(); Object clientData = handle.getClientData(); if (clientData instanceof Node) { if (context.getDriver().isSuppressed(null, issue, (Node) clientData)) { return; } } context.report(issue, location, message); }
@Override public void report(@NonNull Issue issue, @NonNull Location location, @NonNull String message) { if (driver.isSuppressed(this, issue, javaFile)) { return; } super.report(issue, location, message); }
private static boolean isSuppressed( @NonNull JavaContext context, int api, @NonNull PsiElement element, int minSdk) { if (api <= minSdk) { return true; } int target = getTargetApi(element); if (target != -1) { if (api <= target) { return true; } } LintDriver driver = context.getDriver(); return driver.isSuppressed(context, UNSUPPORTED, element) || driver.isSuppressed(context, INLINED, element) || isWithinVersionCheckConditional(element, api) || isPrecededByVersionCheckExit(element, api); }
@Override public void visitElement(@NonNull XmlContext context, @NonNull Element element) { if (SecurityDetector.getExported(element)) { String fqcn = getFqcn(element); if (fqcn != null) { if (fqcn.equals(PREFERENCE_ACTIVITY) && !context.getDriver().isSuppressed(context, ISSUE, element)) { String message = "`PreferenceActivity` should not be exported"; context.report(ISSUE, context.getLocation(element), message); } mExportedActivities.put(fqcn, context.createLocationHandle(element)); } } }
@Override public void visitElement(@NonNull XmlContext context, @NonNull Element element) { if (SecurityDetector.getExported(element)) { String fqcn = getFqcn(element); if (fqcn != null) { if (fqcn.equals(PREFERENCE_ACTIVITY) && !context.getDriver().isSuppressed(context, ISSUE, element)) { String message = "`PreferenceActivity` should not be exported"; context.report(ISSUE, element, context.getLocation(element), message); } mExportedActivities.put(fqcn, context.createLocationHandle(element)); } } }
public void report( @NonNull Issue issue, @Nullable PsiElement scope, @NonNull Location location, @NonNull String message) { if (scope != null && driver.isSuppressed(this, issue, scope)) { return; } super.report(issue, location, message); }
@Override public void visitReference(@NonNull JavaContext context, @Nullable JavaElementVisitor visitor, @NonNull PsiJavaCodeReferenceElement reference, @NonNull PsiElement resolved) { if (resolved instanceof PsiField && context.getEvaluator().isMemberInClass((PsiField) resolved, "android.view.MenuItem")) { if ("SHOW_AS_ACTION_ALWAYS".equals(reference.getReferenceName())) { if (context.getDriver().isSuppressed(context, ISSUE, reference)) { return; } if (mAlwaysFields == null) { mAlwaysFields = new ArrayList<>(); } mAlwaysFields.add(context.getLocation(reference)); } else { mHasIfRoomRefs = true; } } } }
/** * Reports an issue applicable to a given DOM node. The DOM node is used as the * scope to check for suppress lint annotations. * * @param issue the issue to report * @param scope the DOM node scope the error applies to. The lint infrastructure * will check whether there are suppress directives on this node (or its enclosing * nodes) and if so suppress the warning without involving the client. * @param location the location of the issue, or null if not known * @param message the message for this warning */ public void report( @NonNull Issue issue, @Nullable Node scope, @NonNull Location location, @NonNull String message) { if (scope != null && driver.isSuppressed(this, issue, scope)) { return; } super.report(issue, location, message); }
/** * Reports an issue applicable to a given method node. * * @param issue the issue to report * @param field the scope the error applies to. The lint infrastructure * will check whether there are suppress annotations on this field (or its enclosing * class) and if so suppress the warning without involving the client. * @param location the location of the issue, or null if not known * @param message the message for this warning */ public void report( @NonNull Issue issue, @Nullable FieldNode field, @NonNull Location location, @NonNull String message) { if (field != null && driver.isSuppressed(issue, field)) { return; } report(issue, location, message); // also checks the class node }
private void checkClass(@NonNull PsiElement element, @Nullable String descriptor, @NonNull String owner, @NonNull String fqcn) { int api = mApiDatabase.getClassVersion(owner); if (api == -1) { return; } int minSdk = getMinSdk(mContext); if (isSuppressed(mContext, api, element, minSdk)) { return; } // It's okay to reference classes from annotations if (PsiTreeUtil.getParentOfType(element, PsiAnnotation.class) != null) { return; } Location location = mContext.getNameLocation(element); minSdk = Math.max(minSdk, getTargetApi(element)); String message = String.format( "%1$s requires API level %2$d (current min is %3$d): %4$s", descriptor == null ? "Class" : descriptor, api, Math.max(minSdk, getTargetApi(element)), fqcn); mContext.report(UNSUPPORTED, element, location, message); }
/** * Reports an issue applicable to a given AST node. The AST node is used as the * scope to check for suppress lint annotations. * * @param issue the issue to report * @param scope the AST node scope the error applies to. The lint infrastructure * will check whether there are suppress annotations on this node (or its enclosing * nodes) and if so suppress the warning without involving the client. * @param location the location of the issue, or null if not known * @param message the message for this warning */ public void report( @NonNull Issue issue, @Nullable Node scope, @NonNull Location location, @NonNull String message) { if (scope != null && driver.isSuppressed(this, issue, scope)) { return; } super.report(issue, location, message); }
@Override public void afterCheckProject(@NonNull Context context) { if (mPending != null && mWhitelistedLayouts != null) { // Process all the root FrameLayouts that are eligible, and generate // suggestions for <merge> replacements for any layouts that are included // from other layouts for (Pair<String, Handle> pair : mPending) { String layout = pair.getFirst(); if (mWhitelistedLayouts.contains(layout)) { Handle handle = pair.getSecond(); Object clientData = handle.getClientData(); if (clientData instanceof Node) { if (context.getDriver().isSuppressed(null, ISSUE, (Node) clientData)) { return; } } Location location = handle.resolve(); context.report(ISSUE, location, "This `<FrameLayout>` can be replaced with a `<merge>` tag"); } } } }
@Override public void report( @NonNull Issue issue, @NonNull Location location, @NonNull String message) { // Warn if clients use the non-scoped form? No, there are cases where an // XML detector's error isn't applicable to one particular location (or it's // not feasible to compute it cheaply) //driver.getClient().log(null, "Warning: Issue " + issue // + " was reported without a scope node: Can't be suppressed."); // For now just check the document root itself if (document != null && driver.isSuppressed(this, issue, document)) { return; } super.report(issue, location, message); }
public boolean isSuppressed(@Nullable JavaContext context, @NonNull Issue issue, @Nullable PsiElement scope) { boolean checkComments = client.checkForSuppressComments() && context != null && context.containsCommentSuppress(); while (scope != null) { if (scope instanceof PsiModifierListOwner) { PsiModifierListOwner owner = (PsiModifierListOwner) scope; if (isSuppressed(issue, owner.getModifierList())) { return true; } } if (checkComments && context.isSuppressedWithComment(scope, issue)) { return true; } scope = scope.getParent(); if (scope instanceof PsiFile) { return false; } } return false; }
private static boolean isIgnoredInIde(@NonNull Issue issue, @NonNull JavaContext context, @NonNull PsiElement node) { // Historically, the IDE would treat *all* support annotation warnings as // handled by the id "ResourceType", so look for that id too for issues // deliberately suppressed prior to Android Studio 2.0. Issue synonym = Issue.create("ResourceType", issue.getBriefDescription(TextFormat.RAW), issue.getExplanation(TextFormat.RAW), issue.getCategory(), issue.getPriority(), issue.getDefaultSeverity(), issue.getImplementation()); return context.getDriver().isSuppressed(context, synonym, node); }