diff options
5 files changed, 136 insertions, 4 deletions
diff --git a/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefClass.java b/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefClass.java index 3e9044ec5eaf..856285a7bfce 100644 --- a/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefClass.java +++ b/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefClass.java @@ -62,6 +62,9 @@ public interface RefClass extends RefJavaElement { boolean isTestCase(); + /** Returns true if this class extends one of the Android framework classes that must be public */ + boolean isAndroidPublic(); + boolean isLocalClass(); boolean isSelfInheritor(PsiClass psiClass); diff --git a/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefJavaManager.java b/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefJavaManager.java index 51ea666f59fa..9ce3a61b5222 100644 --- a/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefJavaManager.java +++ b/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefJavaManager.java @@ -71,6 +71,19 @@ public abstract class RefJavaManager implements RefManagerExtension<RefJavaManag public abstract PsiClass getServlet(); + // Android Framework APIs that apps extend and where the subclasses must be public + // such that the framework can instantiate them + + public abstract PsiClass getAndroidView(); + public abstract PsiClass getAndroidActivity(); + public abstract PsiClass getAndroidService(); + public abstract PsiClass getAndroidBackupAgent(); + public abstract PsiClass getAndroidContentProvider(); + public abstract PsiClass getAndroidReceiver(); + public abstract PsiClass getAndroidFragment(boolean support); + public abstract PsiClass getAndroidActionProvider(); + public abstract PsiClass getAndroidParcelable(); + public abstract EntryPointsManager getEntryPointsManager(); @NotNull diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefClassImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefClassImpl.java index 13a18f075aa4..ddaeeb7581b5 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefClassImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefClassImpl.java @@ -56,6 +56,7 @@ public class RefClassImpl extends RefJavaElementImpl implements RefClass { private static final int IS_SERVLET_MASK = 0x400000; private static final int IS_TESTCASE_MASK = 0x800000; private static final int IS_LOCAL_MASK = 0x1000000; + private static final int IS_ANDROID_MASK = 0x2000000; private Set<RefClass> myBases; // singleton (to conserve the memory) or THashSet private Set<RefClass> mySubClasses; // singleton (to conserve the memory) or THashSet @@ -139,6 +140,26 @@ public class RefClassImpl extends RefJavaElementImpl implements RefClass { } } + // The Android framework has a number of classes that it wants to + // instantiate so it requires these classes to be public, even if + // code analysis suggests that that these are only referenced from + // within the same package. Unfortunately these do not all extend the + // same set of base classes, so we need to check all these cases + // independently. + RefJavaManager refManager = getRefJavaManager(); + if (inheritsFrom(psiClass, refManager.getAndroidActivity()) + || inheritsFrom(psiClass, refManager.getAndroidService()) + || inheritsFrom(psiClass, refManager.getAndroidView()) + || inheritsFrom(psiClass, refManager.getAndroidFragment(false)) + || inheritsFrom(psiClass, refManager.getAndroidFragment(true)) + || inheritsFrom(psiClass, refManager.getAndroidReceiver()) + || inheritsFrom(psiClass, refManager.getAndroidContentProvider()) + || inheritsFrom(psiClass, refManager.getAndroidParcelable()) + || inheritsFrom(psiClass, refManager.getAndroidBackupAgent()) + || inheritsFrom(psiClass, refManager.getAndroidActionProvider())) { + setAndroidPublic(true); + } + for (PsiMethod psiMethod : psiMethods) { RefMethod refMethod = (RefMethod)getRefManager().getReference(psiMethod); @@ -187,6 +208,10 @@ public class RefClassImpl extends RefJavaElementImpl implements RefClass { } } + private static boolean inheritsFrom(@NotNull PsiClass c1, @Nullable PsiClass c2) { + return c2 != null && c1.isInheritor(c2, true); + } + private static ServerPageFile getJspFile(PsiClass psiClass) { final PsiFile psiFile = PsiUtilCore.getTemplateLanguageFile(psiClass); return psiFile instanceof ServerPageFile ? (ServerPageFile)psiFile : null; @@ -491,6 +516,11 @@ public class RefClassImpl extends RefJavaElementImpl implements RefClass { } @Override + public boolean isAndroidPublic() { + return checkFlag(IS_ANDROID_MASK); + } + + @Override public boolean isTestCase() { return checkFlag(IS_TESTCASE_MASK); } @@ -557,6 +587,10 @@ public class RefClassImpl extends RefJavaElementImpl implements RefClass { setFlag(servlet, IS_SERVLET_MASK); } + private void setAndroidPublic(boolean android) { + setFlag(android, IS_ANDROID_MASK); + } + private void setTestCase(boolean testCase) { setFlag(testCase, IS_TESTCASE_MASK); } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaManagerImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaManagerImpl.java index d9291660f9be..341f44a2fdf3 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaManagerImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaManagerImpl.java @@ -46,6 +46,16 @@ public class RefJavaManagerImpl extends RefJavaManager { private PsiMethod myAppAgentmainPattern; private PsiClass myApplet; private PsiClass myServlet; + private PsiClass myAndroidActivity; + private PsiClass myAndroidService; + private PsiClass myAndroidBackupAgent; + private PsiClass myAndroidFragment; + private PsiClass myAndroidV4Fragment; + private PsiClass myAndroidContentProvider; + private PsiClass myAndroidReceiver; + private PsiClass myAndroidView; + private PsiClass myAndroidActionProvider; + private PsiClass myAndroidParcelable; private RefPackage myDefaultPackage; private THashMap<String, RefPackage> myPackages; private final RefManagerImpl myRefManager; @@ -66,9 +76,23 @@ public class RefJavaManagerImpl extends RefJavaManager { LOG.error(e); } - myApplet = JavaPsiFacade.getInstance(psiManager.getProject()).findClass("java.applet.Applet", GlobalSearchScope.allScope(project)); - myServlet = JavaPsiFacade.getInstance(psiManager.getProject()).findClass("javax.servlet.Servlet", GlobalSearchScope.allScope(project)); - + GlobalSearchScope scope = GlobalSearchScope.allScope(project); + JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(psiManager.getProject()); + myApplet = psiFacade.findClass("java.applet.Applet", scope); + myServlet = psiFacade.findClass("javax.servlet.Servlet", scope); + + // Android Framework APIs that apps extend and where the subclasses must be public + // such that the framework can instantiate them + myAndroidActivity = psiFacade.findClass("android.app.Activity", scope); + myAndroidService = psiFacade.findClass("android.app.Service", scope); + myAndroidFragment = psiFacade.findClass("android.app.Fragment", scope); + myAndroidV4Fragment = psiFacade.findClass("android.support.v4.app.Fragment", scope); + myAndroidContentProvider = psiFacade.findClass("android.content.ContentProvider", scope); + myAndroidReceiver = psiFacade.findClass("android.content.BroadcastReceiver", scope); + myAndroidView = psiFacade.findClass("android.view.View", scope); + myAndroidActionProvider = psiFacade.findClass("android.view.ActionProvider", scope); + myAndroidParcelable = psiFacade.findClass("android.os.Parcelable", scope); + myAndroidBackupAgent = psiFacade.findClass("android.app.backup.BackupAgent", scope); } @Override @@ -158,6 +182,51 @@ public class RefJavaManagerImpl extends RefJavaManager { } @Override + public PsiClass getAndroidActivity() { + return myAndroidActivity; + } + + @Override + public PsiClass getAndroidService() { + return myAndroidService; + } + + @Override + public PsiClass getAndroidBackupAgent() { + return myAndroidBackupAgent; + } + + @Override + public PsiClass getAndroidFragment(boolean support) { + return support ? myAndroidV4Fragment : myAndroidFragment; + } + + @Override + public PsiClass getAndroidContentProvider() { + return myAndroidContentProvider; + } + + @Override + public PsiClass getAndroidReceiver() { + return myAndroidReceiver; + } + + @Override + public PsiClass getAndroidView() { + return myAndroidView; + } + + @Override + public PsiClass getAndroidActionProvider() { + return myAndroidActionProvider; + } + + @Override + public PsiClass getAndroidParcelable() { + return myAndroidParcelable; + } + + @Override public RefParameter getParameterReference(PsiParameter param, int index) { LOG.assertTrue(myRefManager.isValidPointForReference(), "References may become invalid after process is finished"); RefElement ref = myRefManager.getFromRefTable(param); @@ -203,6 +272,16 @@ public class RefJavaManagerImpl extends RefJavaManager { myAppPremainPattern = null; myAppAgentmainPattern = null; myServlet = null; + myAndroidActivity = null; + myAndroidService = null; + myAndroidBackupAgent = null; + myAndroidFragment = null; + myAndroidV4Fragment = null; + myAndroidContentProvider = null; + myAndroidReceiver = null; + myAndroidView = null; + myAndroidActionProvider = null; + myAndroidParcelable = null; myDefaultPackage = null; myProjectIterator = null; } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/visibility/VisibilityInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/visibility/VisibilityInspection.java index fd66f2806cb9..aa772f337610 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/visibility/VisibilityInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/visibility/VisibilityInspection.java @@ -44,7 +44,6 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.usageView.UsageViewTypeLocation; import com.intellij.util.IncorrectOperationException; -import com.intellij.util.VisibilityUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -179,6 +178,10 @@ public class VisibilityInspection extends GlobalJavaBatchInspectionTool { RefClass refClass = (RefClass) refElement; if (refClass.isAnonymous() || refClass.isEntry() || refClass.isTestCase() || refClass.isServlet() || refClass.isApplet() || refClass.isLocalClass()) return null; if (isTopLevelClass(refClass) && !SUGGEST_PACKAGE_LOCAL_FOR_TOP_CLASSES) return null; + + if (refClass.isAndroidPublic()) { + return null; + } } //ignore unreferenced code. They could be a potential entry points. |