private ApiVisitor(JavaContext context) { mContext = context; LintDriver driver = context.getDriver(); boolean isInIde = !driver.getScope().contains(Scope.CLASS_FILE); // @RequiresApi is already enforced by the ResourceTypeInspection when running in the IDE checkRequiresApi = !isInIde; // If there are resolution errors and we have bytecode, // let the class scanner handle itself. willScanBytecode = driver.hasParserErrors() && !isInIde; }
@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); } }
@Nullable @Override public JavaElementVisitor createPsiVisitor(@NonNull JavaContext context) { if (context.getDriver().getPhase() == 1) { return new UnusedResourceVisitor(); } else { // Second pass, computing resource declaration locations: No need to look at Java return null; } }
@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; } } } }
private boolean checkSuppressLint(@NonNull PsiAnnotation node, @NonNull String id) { IssueRegistry registry = mContext.getDriver().getRegistry(); Issue issue = registry.getIssue(id); // Special-case the ApiDetector issue, since it does both source file analysis // only on field references, and class file analysis on the rest, so we allow // annotations outside of methods only on fields if (issue != null && !issue.getImplementation().getScope().contains(Scope.JAVA_FILE) || issue == ApiDetector.UNSUPPORTED) { // This issue doesn't have AST access: annotations are not // available for local variables or parameters PsiElement scope = getAnnotationScope(node); mContext.report(INSIDE_METHOD, scope, mContext.getLocation(node), String.format( "The `@SuppressLint` annotation cannot be used on a local " + "variable with the lint check '%1$s': move out to the " + "surrounding method", id)); return false; } return true; } }
String message = String.format("Try-with-resources requires " + "API level %1$d (current min is %2$d)", api, minSdk); LintDriver driver = mContext.getDriver(); if (!driver.isSuppressed(mContext, UNSUPPORTED, node)) { mContext.report(UNSUPPORTED, location, message); "Class requires API level %1$d (current min is %2$d): `%3$s`", api, minSdk, fqcn); LintDriver driver = mContext.getDriver(); if (!driver.isSuppressed(mContext, UNSUPPORTED, typeReference)) { mContext.report(UNSUPPORTED, location, message);
/** * Checks a String.format call that is using a string that doesn't contain format placeholders. * @param context the context to report errors to * @param call the AST node for the {@link String#format} * @param name the string name * @param handle the string location */ private static void checkNotFormattedHandle( JavaContext context, PsiMethodCallExpression call, String name, Handle handle) { Object clientData = handle.getClientData(); if (clientData instanceof Node) { if (context.getDriver().isSuppressed(null, INVALID, (Node) clientData)) { return; } } Location location = context.getLocation(call); Location secondary = handle.resolve(); secondary.setMessage("This definition does not require arguments"); location.setSecondary(secondary); String message = String.format( "Format string '`%1$s`' is not a valid format string so it should not be " + "passed to `String.format`", name); context.report(INVALID, call, location, message); }
Object clientData = handle.getClientData(); if (clientData instanceof Node) { if (context.getDriver().isSuppressed(null, INVALID, (Node) clientData)) { return;
if (!context.getDriver().isSuppressed(context, ISSUE, node)) { if (mPendingErrors == null) { mPendingErrors = Lists.newArrayList();
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); }
private boolean checkId(Annotation node, String id) { IssueRegistry registry = mContext.getDriver().getRegistry(); Issue issue = registry.getIssue(id);
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); }
if (!context.getDriver().isSuppressed(context, ISSUE, call)) { if (mPendingErrors == null) { mPendingErrors = Lists.newArrayList();
if (mContext.getDriver().isSuppressed(mContext, OVERRIDE, method)) { return;
/** * Returns a {@link Location} for the given element * * @param context information about the file being parsed * @param element the element to create a location for * @return a location for the given node */ @SuppressWarnings("MethodMayBeStatic") // subclasses may want to override/optimize @NonNull public Location getLocation(@NonNull JavaContext context, @NonNull PsiElement element) { TextRange range = element.getTextRange(); PsiFile containingFile = element.getContainingFile(); File file = context.file; CharSequence contents = context.getContents(); if (containingFile != context.getJavaFile()) { // Reporting an error in a different file. if (context.getDriver().getScope().size() == 1) { // Don't bother with this error if it's in a different file during single-file analysis return Location.NONE; } File ioFile = getFile(containingFile); if (ioFile == null) { return Location.NONE; } file = ioFile; contents = getFileContents(containingFile); } return Location.create(file, contents, range.getStartOffset(), range.getEndOffset()); }
api, minSdk, fqcn); LintDriver driver = mContext.getDriver(); if (driver.isSuppressed(mContext, INLINED, node)) { return true;