blob: 96baf95165eeba200aad0a4cc20b4b4267f42f96 [file] [log] [blame]
package org.jetbrains.android;
import com.intellij.openapi.module.impl.scopes.JdkScope;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.JdkOrderEntry;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.CommonClassNames;
import com.intellij.psi.SdkResolveScopeProvider;
import com.intellij.psi.search.GlobalSearchScope;
import org.jetbrains.android.augment.AndroidInternalRClass;
import org.jetbrains.android.sdk.AndroidSdkType;
import org.jetbrains.annotations.NotNull;
/**
* @author Eugene.Kudelevsky
*/
public class AndroidSdkResolveScopeProvider extends SdkResolveScopeProvider {
@Override
public GlobalSearchScope getScope(@NotNull Project project, @NotNull JdkOrderEntry entry) {
final Sdk sdk = entry.getJdk();
if (sdk == null || !(sdk.getSdkType() instanceof AndroidSdkType)) {
return null;
}
if (sdk.getRootProvider().getFiles(OrderRootType.SOURCES).length == 0) {
return null;
}
return new MyJdkScope(project, entry);
}
public static class MyJdkScope extends JdkScope {
private final Sdk mySdk;
private MyJdkScope(Project project, @NotNull JdkOrderEntry jdkOrderEntry) {
super(project, jdkOrderEntry);
mySdk = jdkOrderEntry.getJdk();
}
@Override
public boolean isForceSearchingInLibrarySources() {
return true;
}
@Override
public int compare(@NotNull VirtualFile file1, @NotNull VirtualFile file2) {
final boolean inSources1 = myIndex.isInLibrarySource(file1);
if (inSources1 != myIndex.isInLibrarySource(file2)) {
//Consider class A implements Runnable in project source.
//Super class Object for class A is found in cls, super interface Runnable is found in cls as well (class A resolve scope is simple modules scope with dependencies).
//Super class of cls Runnable isn't explicitly specified in the cls psi, so PsiClassImplUtil.getSuperClass/getSuperTypes return java.lang.Object
//found via file's resolve scope (this one). So for the two hierarchies to meet in one place we should return cls Object here.
//By default this resolve scope prefers sdk sources, so we need to override this behavior for Object.
//The problem doesn't arise for other super class references inside Android sdk cls (e.g. A extends B implements C, where B implements C and both are inside android sdk),
//because these references (C) are explicit and resolved via ClsJavaCodeReferenceElementImpl#resolveClassPreferringMyJar which returns cls classes despite custom Android sdk scope.
if (!CommonClassNames.JAVA_LANG_OBJECT_SHORT.equals(file1.getNameWithoutExtension())) {
return inSources1 ? 1 : -1;
}
}
return super.compare(file1, file2);
}
@Override
public boolean contains(@NotNull VirtualFile file) {
return super.contains(file) || AndroidInternalRClass.isAndroidInternalR(file, mySdk);
}
}
}