From 09cafea14218cb1eebb433a482ddb0c434d0c27a Mon Sep 17 00:00:00 2001 From: Eugene Kudelevsky Date: Fri, 20 Jul 2012 20:42:13 +0400 Subject: [PATCH] android dependency processor: search for refs to R class instead of usages of each constant field (inside project they may be non-existent or non-up-to date) --- .../compiler/DependencyProcessor.java | 4 +- .../compiler/make/DependencyCache.java | 2 +- .../android/util/AndroidCommonUtils.java | 2 +- plugins/android/src/META-INF/plugin.xml | 1 + .../compiler/AndroidDependencyProcessor.java | 88 +++++++++++++++++++ 5 files changed, 94 insertions(+), 3 deletions(-) create mode 100644 plugins/android/src/org/jetbrains/android/compiler/AndroidDependencyProcessor.java diff --git a/java/compiler/impl/src/com/intellij/compiler/DependencyProcessor.java b/java/compiler/impl/src/com/intellij/compiler/DependencyProcessor.java index dbf3703c2337..3907eb81c040 100644 --- a/java/compiler/impl/src/com/intellij/compiler/DependencyProcessor.java +++ b/java/compiler/impl/src/com/intellij/compiler/DependencyProcessor.java @@ -15,6 +15,8 @@ */ package com.intellij.compiler; +import com.intellij.compiler.make.CacheCorruptedException; +import com.intellij.compiler.make.CachingSearcher; import com.intellij.openapi.compiler.CompileContext; import com.intellij.openapi.extensions.ExtensionPointName; @@ -25,5 +27,5 @@ import com.intellij.openapi.extensions.ExtensionPointName; public interface DependencyProcessor { ExtensionPointName EXTENSION_POINT_NAME = ExtensionPointName.create("com.intellij.compiler.makeDependencyProcessor"); - void processDependencies(CompileContext context, int classQualifiedName); + void processDependencies(CompileContext context, int classQualifiedName, CachingSearcher searcher) throws CacheCorruptedException; } diff --git a/java/compiler/impl/src/com/intellij/compiler/make/DependencyCache.java b/java/compiler/impl/src/com/intellij/compiler/make/DependencyCache.java index dab0f311254e..92f3285bf8ef 100644 --- a/java/compiler/impl/src/com/intellij/compiler/make/DependencyCache.java +++ b/java/compiler/impl/src/com/intellij/compiler/make/DependencyCache.java @@ -429,7 +429,7 @@ public class DependencyCache { } changedRetentionPolicyDependencyProcessor.checkAnnotationRetentionPolicyChanges(qName); for (DependencyProcessor additionalProcessor : DependencyProcessor.EXTENSION_POINT_NAME.getExtensions()) { - additionalProcessor.processDependencies(context, qName); + additionalProcessor.processDependencies(context, qName, searcher); } } else { diff --git a/plugins/android/common/src/org/jetbrains/android/util/AndroidCommonUtils.java b/plugins/android/common/src/org/jetbrains/android/util/AndroidCommonUtils.java index 4bf3ff099498..3be8392b3e29 100644 --- a/plugins/android/common/src/org/jetbrains/android/util/AndroidCommonUtils.java +++ b/plugins/android/common/src/org/jetbrains/android/util/AndroidCommonUtils.java @@ -61,7 +61,7 @@ public class AndroidCommonUtils { private static final Pattern ERROR_PATTERN = Pattern.compile(".*error.*"); private static final Pattern EXCEPTION_PATTERN = Pattern.compile(".*exception.*"); - private static final Pattern R_PATTERN = Pattern.compile("R(\\$.*)?\\.class"); + public static final Pattern R_PATTERN = Pattern.compile("R(\\$.*)?\\.class"); private static final Pattern MANIFEST_PATTERN = Pattern.compile("Manifest(\\$.*)?\\.class"); private static final String BUILD_CONFIG_CLASS_NAME = "BuildConfig.class"; diff --git a/plugins/android/src/META-INF/plugin.xml b/plugins/android/src/META-INF/plugin.xml index dfade9b013a2..a08133a02f03 100644 --- a/plugins/android/src/META-INF/plugin.xml +++ b/plugins/android/src/META-INF/plugin.xml @@ -143,6 +143,7 @@ + diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidDependencyProcessor.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidDependencyProcessor.java new file mode 100644 index 000000000000..7423d5fdf7a0 --- /dev/null +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidDependencyProcessor.java @@ -0,0 +1,88 @@ +package org.jetbrains.android.compiler; + +import com.intellij.compiler.DependencyProcessor; +import com.intellij.compiler.make.*; +import com.intellij.facet.ProjectFacetManager; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.compiler.CompileContext; +import com.intellij.openapi.compiler.ex.CompileContextEx; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.util.containers.HashSet; +import org.jetbrains.android.facet.AndroidFacet; +import org.jetbrains.android.util.AndroidCommonUtils; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.util.Collection; +import java.util.Set; + +/** + * @author Eugene.Kudelevsky + */ +public class AndroidDependencyProcessor implements DependencyProcessor { + @Override + public void processDependencies(final CompileContext context, int classQualifiedName, final CachingSearcher searcher) + throws CacheCorruptedException { + if (!(context instanceof CompileContextEx)) { + return; + } + final Project project = context.getProject(); + + if (!ProjectFacetManager.getInstance(project).hasFacets(AndroidFacet.ID)) { + return; + } + final DependencyCache depCache = ((CompileContextEx)context).getDependencyCache(); + final Cache cache = depCache.getCache(); + final String path = cache.getPath(classQualifiedName); + final String classFileName = new File(path).getName(); + + if (!AndroidCommonUtils.R_PATTERN.matcher(classFileName).matches()) { + return; + } + final String qName = depCache.resolve(classQualifiedName); + final int idx = qName.indexOf('$'); + final String topLevelClassName = idx < 0 ? qName : qName.substring(0, idx); + final Set qNamesToMark = new HashSet(); + + ApplicationManager.getApplication().runReadAction(new Runnable() { + @Override + public void run() { + final PsiClass[] classes = + JavaPsiFacade.getInstance(project).findClasses(topLevelClassName, GlobalSearchScope.allScope(project)); + + for (PsiClass aClass : classes) { + final Collection references = searcher.findReferences(aClass, true); + + for (PsiReference reference : references) { + final PsiClass ownerClass = getOwnerClass(reference.getElement()); + if (ownerClass != null && !ownerClass.equals(aClass)) { + final String ownerClassQName = ownerClass.getQualifiedName(); + + if (ownerClassQName != null) { + qNamesToMark.add(ownerClassQName); + } + } + } + } + } + }); + + for (String toMark : qNamesToMark) { + final int qualifiedName = depCache.getSymbolTable().getId(toMark); + depCache.markClass(qualifiedName); + } + } + + @Nullable + private static PsiClass getOwnerClass(PsiElement element) { + while (!(element instanceof PsiFile)) { + if (element instanceof PsiClass && element.getParent() instanceof PsiJavaFile) { + return (PsiClass)element; + } + element = element.getParent(); + } + return null; + } +}