| // Copyright 2018 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| package org.chromium.tools.errorprone.plugin; |
| |
| import static com.google.errorprone.matchers.Matchers.instanceMethod; |
| |
| import com.google.auto.service.AutoService; |
| import com.google.errorprone.BugPattern; |
| import com.google.errorprone.VisitorState; |
| import com.google.errorprone.bugpatterns.BugChecker; |
| import com.google.errorprone.matchers.Description; |
| import com.google.errorprone.matchers.Matcher; |
| import com.google.errorprone.suppliers.Supplier; |
| import com.google.errorprone.suppliers.Suppliers; |
| import com.sun.source.tree.ExpressionTree; |
| import com.sun.source.tree.MethodInvocationTree; |
| import com.sun.tools.javac.code.Type; |
| |
| /** |
| * Checks for calls to getApplicationContext from {@link android.content.Context}. |
| * These calls should be replaced with the static getApplicationContext method in |
| * {@link org.chromium.base.ContextUtils}. |
| */ |
| @AutoService(BugChecker.class) |
| @BugPattern(name = "NoContextGetApplicationContext", |
| summary = "Do not use Context#getApplicationContext", |
| severity = BugPattern.SeverityLevel.ERROR, linkType = BugPattern.LinkType.CUSTOM, |
| link = "https://bugs.chromium.org/p/chromium/issues/detail?id=560466") |
| public class NoContextGetApplicationContext |
| extends BugChecker implements BugChecker.MethodInvocationTreeMatcher { |
| private static final String CONTEXT_CLASS_NAME = "android.content.Context"; |
| private static final String CONTEXT_UTILS_CLASS_NAME = "org.chromium.base.ContextUtils"; |
| private static final String METHOD_NAME = "getApplicationContext"; |
| |
| private static final Supplier<Type> CONTEXT_UTILS_SUPPLIER = |
| Suppliers.typeFromString(CONTEXT_UTILS_CLASS_NAME); |
| private static final Matcher<ExpressionTree> CONTEXT_MATCHER = |
| instanceMethod() |
| .onDescendantOf(Suppliers.typeFromString(CONTEXT_CLASS_NAME)) |
| .named(METHOD_NAME); |
| |
| @Override |
| public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState visitorState) { |
| if (!CONTEXT_MATCHER.matches(tree, visitorState)) { |
| return Description.NO_MATCH; |
| } |
| |
| // If ContextUtils can't be loaded, we are probably inside a third_party lib and shouldn't |
| // check for errors. |
| boolean canLoadContextUtils = CONTEXT_UTILS_SUPPLIER.get(visitorState) != null; |
| if (!canLoadContextUtils) { |
| return Description.NO_MATCH; |
| } |
| |
| return buildDescription(tree) |
| .setMessage("Don't use Context#getApplicationContext - " |
| + "call ContextUtils.getApplicationContext instead") |
| .build(); |
| } |
| } |