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)

This commit is contained in:
Eugene Kudelevsky
2012-07-23 14:53:47 +04:00
parent 5982b9f440
commit 09cafea142
5 changed files with 94 additions and 3 deletions
@@ -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<DependencyProcessor> 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;
}
@@ -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 {
@@ -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";
+1
View File
@@ -143,6 +143,7 @@
<compiler implementation="org.jetbrains.android.compiler.AndroidPngFilesCachingCompiler"/>
<compiler implementation="org.jetbrains.android.compiler.AndroidResourcesPackagingCompiler"/>
<compiler implementation="org.jetbrains.android.compiler.AndroidPackagingCompiler"/>
<compiler.makeDependencyProcessor implementation="org.jetbrains.android.compiler.AndroidDependencyProcessor"/>
<completion.contributor language="XML" implementationClass="org.jetbrains.android.AndroidCompletionContributor"
id="compositieAttributeValues" order="first"/>
@@ -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<String> qNamesToMark = new HashSet<String>();
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<PsiReference> 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;
}
}