J2K IDELightClassGenerationSupport: autoconvert

This commit is contained in:
Pavel V. Talanov
2015-09-07 15:14:09 +03:00
parent c37b15d629
commit d1d18618b5
@@ -14,514 +14,418 @@
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.caches.resolve;
package org.jetbrains.kotlin.idea.caches.resolve
import com.intellij.ide.highlighter.JavaClassFileType;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.libraries.LibraryUtil;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.ClassFileViewProvider;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiManager;
import com.intellij.psi.impl.compiled.ClsClassImpl;
import com.intellij.psi.impl.compiled.ClsFileImpl;
import com.intellij.psi.impl.java.stubs.PsiJavaFileStub;
import com.intellij.psi.impl.java.stubs.impl.PsiJavaFileStubImpl;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.stubs.PsiClassHolderFileStub;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.cls.ClsFormatException;
import kotlin.KotlinPackage;
import kotlin.jvm.functions.Function1;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.asJava.*;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.idea.decompiler.navigation.JetSourceNavigationHelper;
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade;
import org.jetbrains.kotlin.idea.stubindex.JetFullClassNameIndex;
import org.jetbrains.kotlin.idea.stubindex.JetTopLevelClassByPackageIndex;
import org.jetbrains.kotlin.idea.stubindex.PackageIndexUtil;
import org.jetbrains.kotlin.idea.stubindex.StaticFacadeIndexUtil;
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil;
import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.psi.psiUtil.PsiUtilPackage;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.lazy.*;
import org.jetbrains.kotlin.resolve.scopes.JetScope;
import com.intellij.ide.highlighter.JavaClassFileType
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.libraries.LibraryUtil
import com.intellij.openapi.util.Key
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.ClassFileViewProvider
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiManager
import com.intellij.psi.impl.compiled.ClsClassImpl
import com.intellij.psi.impl.compiled.ClsFileImpl
import com.intellij.psi.impl.java.stubs.PsiJavaFileStub
import com.intellij.psi.impl.java.stubs.impl.PsiJavaFileStubImpl
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.stubs.PsiClassHolderFileStub
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.util.cls.ClsFormatException
import kotlin.KotlinPackage
import org.jetbrains.kotlin.asJava.*
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.decompiler.navigation.JetSourceNavigationHelper
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.stubindex.JetFullClassNameIndex
import org.jetbrains.kotlin.idea.stubindex.JetTopLevelClassByPackageIndex
import org.jetbrains.kotlin.idea.stubindex.PackageIndexUtil
import org.jetbrains.kotlin.idea.stubindex.StaticFacadeIndexUtil
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.lazy.*
import org.jetbrains.kotlin.resolve.scopes.JetScope
import java.io.IOException;
import java.util.*;
import java.io.IOException
import java.util.*
import static kotlin.KotlinPackage.*;
import static org.jetbrains.kotlin.idea.stubindex.JetSourceFilterScope.kotlinSourceAndClassFiles;
import static org.jetbrains.kotlin.idea.stubindex.JetSourceFilterScope.kotlinSourcesAndLibraries;
import kotlin.KotlinPackage.*
import org.jetbrains.kotlin.idea.stubindex.JetSourceFilterScope.kotlinSourceAndClassFiles
import org.jetbrains.kotlin.idea.stubindex.JetSourceFilterScope.kotlinSourcesAndLibraries
public class IDELightClassGenerationSupport extends LightClassGenerationSupport {
public class IDELightClassGenerationSupport(private val project: Project) : LightClassGenerationSupport() {
private static final Logger LOG = Logger.getInstance(IDELightClassGenerationSupport.class);
private val scopeFileComparator: Comparator<PsiElement>
private val psiManager: PsiManager
private final Project project;
private final Comparator<PsiElement> scopeFileComparator;
private final PsiManager psiManager;
public IDELightClassGenerationSupport(@NotNull Project project) {
this.project = project;
this.scopeFileComparator = JavaElementFinder.byClasspathComparator(GlobalSearchScope.allScope(project));
this.psiManager = PsiManager.getInstance(project);
init {
this.scopeFileComparator = JavaElementFinder.byClasspathComparator(GlobalSearchScope.allScope(project))
this.psiManager = PsiManager.getInstance(project)
}
@NotNull
@Override
public LightClassConstructionContext getContextForPackage(@NotNull Collection<JetFile> files) {
assert !files.isEmpty() : "No files in package";
override fun getContextForPackage(files: Collection<JetFile>): LightClassConstructionContext {
assert(!files.isEmpty(), "No files in package")
return getContextForFiles(files);
return getContextForFiles(files)
}
@NotNull
private LightClassConstructionContext getContextForFiles(@NotNull Collection<JetFile> files) {
List<JetFile> sortedFiles = new ArrayList<JetFile>(files);
Collections.sort(sortedFiles, scopeFileComparator);
private fun getContextForFiles(files: Collection<JetFile>): LightClassConstructionContext {
val sortedFiles = ArrayList(files)
Collections.sort(sortedFiles, scopeFileComparator)
JetFile file = sortedFiles.get(0);
ResolveSession resolveSession = ResolvePackage.getResolutionFacade(file).getFrontendService(ResolveSession.class);
forceResolvePackageDeclarations(files, resolveSession);
return new LightClassConstructionContext(resolveSession.getBindingContext(), resolveSession.getModuleDescriptor());
val file = sortedFiles.get(0)
val resolveSession = file.getResolutionFacade().getFrontendService(javaClass<ResolveSession>())
forceResolvePackageDeclarations(files, resolveSession)
return LightClassConstructionContext(resolveSession.bindingContext, resolveSession.getModuleDescriptor())
}
@NotNull
@Override
public LightClassConstructionContext getContextForClassOrObject(@NotNull JetClassOrObject classOrObject) {
ResolutionFacade resolutionFacade = ResolvePackage.getResolutionFacade(classOrObject);
override fun getContextForClassOrObject(classOrObject: JetClassOrObject): LightClassConstructionContext {
val resolutionFacade = classOrObject.getResolutionFacade()
ModuleDescriptor moduleDescriptor = resolutionFacade.getModuleDescriptor();
BindingContext bindingContext = resolutionFacade.analyze(classOrObject, BodyResolveMode.FULL);
val moduleDescriptor = resolutionFacade.moduleDescriptor
val bindingContext = resolutionFacade.analyze(classOrObject, BodyResolveMode.FULL)
if (classOrObject.isLocal()) {
ClassDescriptor descriptor = bindingContext.get(BindingContext.CLASS, classOrObject);
val descriptor = bindingContext.get(BindingContext.CLASS, classOrObject)
if (descriptor == null) {
LOG.warn("No class descriptor in context for class: " + PsiUtilPackage.getElementTextWithContext(classOrObject));
return new LightClassConstructionContext(bindingContext, moduleDescriptor);
LOG.warn("No class descriptor in context for class: " + classOrObject.getElementTextWithContext())
return LightClassConstructionContext(bindingContext, moduleDescriptor)
}
ForceResolveUtil.forceResolveAllContents(descriptor);
ForceResolveUtil.forceResolveAllContents<ClassDescriptor>(descriptor)
return new LightClassConstructionContext(bindingContext, moduleDescriptor);
return LightClassConstructionContext(bindingContext, moduleDescriptor)
}
ForceResolveUtil.forceResolveAllContents(resolutionFacade.resolveToDescriptor(classOrObject));
return new LightClassConstructionContext(bindingContext, moduleDescriptor);
ForceResolveUtil.forceResolveAllContents(resolutionFacade.resolveToDescriptor(classOrObject))
return LightClassConstructionContext(bindingContext, moduleDescriptor)
}
@NotNull
@Override
public LightClassConstructionContext getContextForFacade(@NotNull Collection<JetFile> files) {
assert !files.isEmpty() : "No files in facade";
override fun getContextForFacade(files: Collection<JetFile>): LightClassConstructionContext {
assert(!files.isEmpty(), "No files in facade")
return getContextForFiles(files);
return getContextForFiles(files)
}
private static void forceResolvePackageDeclarations(@NotNull Collection<JetFile> files, @NotNull KotlinCodeAnalyzer session) {
for (JetFile file : files) {
// SCRIPT: not supported
if (file.isScript()) continue;
FqName packageFqName = file.getPackageFqName();
// make sure we create a package descriptor
PackageViewDescriptor packageDescriptor = session.getModuleDescriptor().getPackage(packageFqName);
if (packageDescriptor.isEmpty()) {
LOG.warn("No descriptor found for package " + packageFqName + " in file " + file.getName() + "\n" + file.getText());
session.forceResolveAll();
continue;
}
for (JetDeclaration declaration : file.getDeclarations()) {
if (declaration instanceof JetFunction) {
JetFunction jetFunction = (JetFunction) declaration;
Name name = jetFunction.getNameAsSafeName();
Collection<FunctionDescriptor> functions = packageDescriptor.getMemberScope().getFunctions(name, NoLookupLocation.FROM_IDE);
for (FunctionDescriptor descriptor : functions) {
ForceResolveUtil.forceResolveAllContents(descriptor);
}
}
else if (declaration instanceof JetProperty) {
JetProperty jetProperty = (JetProperty) declaration;
Name name = jetProperty.getNameAsSafeName();
Collection<VariableDescriptor> properties = packageDescriptor.getMemberScope().getProperties(name, NoLookupLocation.FROM_IDE);
for (VariableDescriptor descriptor : properties) {
ForceResolveUtil.forceResolveAllContents(descriptor);
}
}
else if (declaration instanceof JetClassOrObject) {
// Do nothing: we are not interested in classes
}
else {
LOG.error("Unsupported declaration kind: " + declaration + " in file " + file.getName() + "\n" + file.getText());
}
}
}
override fun findClassOrObjectDeclarations(fqName: FqName, searchScope: GlobalSearchScope): Collection<JetClassOrObject> {
return JetFullClassNameIndex.getInstance().get(fqName.asString(), project, kotlinSourceAndClassFiles(searchScope, project))
}
@NotNull
@Override
public Collection<JetClassOrObject> findClassOrObjectDeclarations(@NotNull FqName fqName, @NotNull GlobalSearchScope searchScope) {
return JetFullClassNameIndex.getInstance().get(fqName.asString(), project, kotlinSourceAndClassFiles(searchScope, project));
override fun findFilesForPackage(fqName: FqName, searchScope: GlobalSearchScope): Collection<JetFile> {
return PackageIndexUtil.findFilesWithExactPackage(fqName, kotlinSourceAndClassFiles(searchScope, project), project)
}
@NotNull
@Override
public Collection<JetFile> findFilesForPackage(@NotNull FqName fqName, @NotNull GlobalSearchScope searchScope) {
return PackageIndexUtil.findFilesWithExactPackage(fqName, kotlinSourceAndClassFiles(searchScope, project), project);
}
@NotNull
@Override
public Collection<JetClassOrObject> findClassOrObjectDeclarationsInPackage(
@NotNull FqName packageFqName, @NotNull GlobalSearchScope searchScope
) {
override fun findClassOrObjectDeclarationsInPackage(
packageFqName: FqName, searchScope: GlobalSearchScope): Collection<JetClassOrObject> {
return JetTopLevelClassByPackageIndex.getInstance().get(
packageFqName.asString(), project, kotlinSourceAndClassFiles(searchScope, project)
);
packageFqName.asString(), project, kotlinSourceAndClassFiles(searchScope, project))
}
@Override
public boolean packageExists(@NotNull FqName fqName, @NotNull GlobalSearchScope scope) {
return PackageIndexUtil.packageExists(fqName, kotlinSourceAndClassFiles(scope, project), project);
override fun packageExists(fqName: FqName, scope: GlobalSearchScope): Boolean {
return PackageIndexUtil.packageExists(fqName, kotlinSourceAndClassFiles(scope, project), project)
}
@NotNull
@Override
public Collection<FqName> getSubPackages(@NotNull FqName fqn, @NotNull GlobalSearchScope scope) {
return PackageIndexUtil.getSubPackageFqNames(fqn, kotlinSourceAndClassFiles(scope, project), project, JetScope.ALL_NAME_FILTER);
override fun getSubPackages(fqn: FqName, scope: GlobalSearchScope): Collection<FqName> {
return PackageIndexUtil.getSubPackageFqNames(fqn, kotlinSourceAndClassFiles(scope, project), project, JetScope.ALL_NAME_FILTER)
}
@Nullable
@Override
public PsiClass getPsiClass(@NotNull JetClassOrObject classOrObject) {
VirtualFile virtualFile = classOrObject.getContainingFile().getVirtualFile();
if (virtualFile != null && LibraryUtil.findLibraryEntry(virtualFile, classOrObject.getProject()) != null) {
override fun getPsiClass(classOrObject: JetClassOrObject): PsiClass? {
val virtualFile = classOrObject.containingFile.virtualFile
if (virtualFile != null && LibraryUtil.findLibraryEntry(virtualFile, classOrObject.project) != null) {
if (ProjectRootsUtil.isLibraryClassFile(project, virtualFile)) {
return getLightClassForDecompiledClassOrObject(classOrObject);
return getLightClassForDecompiledClassOrObject(classOrObject)
}
return JetSourceNavigationHelper.getOriginalClass(classOrObject);
return JetSourceNavigationHelper.getOriginalClass(classOrObject)
}
return KotlinLightClassForExplicitDeclaration.Companion.create(psiManager, classOrObject);
return KotlinLightClassForExplicitDeclaration.create(psiManager, classOrObject)
}
@Nullable
private static PsiClass getLightClassForDecompiledClassOrObject(@NotNull JetClassOrObject decompiledClassOrObject) {
if (decompiledClassOrObject instanceof JetEnumEntry) {
return null;
}
JetFile containingJetFile = decompiledClassOrObject.getContainingJetFile();
if (!containingJetFile.isCompiled()) {
return null;
}
PsiClass rootLightClassForDecompiledFile = createLightClassForDecompiledKotlinFile(containingJetFile);
if (rootLightClassForDecompiledFile == null) return null;
override fun getPackageClasses(packageFqName: FqName, scope: GlobalSearchScope): Collection<PsiClass> {
val result = ArrayList<PsiClass>()
val packageClassesInfos = findPackageClassesInfos(packageFqName, scope)
for (info in packageClassesInfos) {
val files = PackagePartClassUtils.getFilesWithCallables(info.files)
if (files.isEmpty()) continue
return findCorrespondingLightClass(decompiledClassOrObject, rootLightClassForDecompiledFile);
}
@NotNull
private static PsiClass findCorrespondingLightClass(
@NotNull JetClassOrObject decompiledClassOrObject,
@NotNull PsiClass rootLightClassForDecompiledFile
) {
FqName relativeFqName = getClassRelativeName(decompiledClassOrObject);
Iterator<Name> iterator = relativeFqName.pathSegments().iterator();
Name base = iterator.next();
assert rootLightClassForDecompiledFile.getName().equals(base.asString())
: "Light class for file:\n" + decompiledClassOrObject.getContainingJetFile().getVirtualFile().getCanonicalPath()
+ "\nwas expected to have name: " + base.asString() + "\n Actual: " + rootLightClassForDecompiledFile.getName();
PsiClass current = rootLightClassForDecompiledFile;
while (iterator.hasNext()) {
Name name = iterator.next();
PsiClass innerClass = current.findInnerClassByName(name.asString(), false);
assert innerClass != null : "Could not find corresponding inner/nested class " + relativeFqName + " in class " + decompiledClassOrObject.getFqName() + "\n" +
"File: " + decompiledClassOrObject.getContainingJetFile().getVirtualFile().getName();
current = innerClass;
}
return current;
}
@NotNull
private static FqName getClassRelativeName(@NotNull JetClassOrObject decompiledClassOrObject) {
Name name = decompiledClassOrObject.getNameAsName();
assert name != null;
JetClassOrObject parent = PsiTreeUtil.getParentOfType(decompiledClassOrObject, JetClassOrObject.class, true);
if (parent == null) {
assert decompiledClassOrObject.isTopLevel();
return FqName.topLevel(name);
}
return getClassRelativeName(parent).child(name);
}
@NotNull
@Override
public Collection<PsiClass> getPackageClasses(@NotNull FqName packageFqName, @NotNull GlobalSearchScope scope) {
List<PsiClass> result = new ArrayList<PsiClass>();
List<KotlinLightFacadeClassInfo> packageClassesInfos = findPackageClassesInfos(packageFqName, scope);
for (KotlinLightFacadeClassInfo info : packageClassesInfos) {
List<JetFile> files = PackagePartClassUtils.getFilesWithCallables(info.getFiles());
if (files.isEmpty()) continue;
IdeaModuleInfo moduleInfo = info.getModuleInfo();
if (moduleInfo instanceof ModuleSourceInfo) {
result.addAll(getLightClassesForPackageFacadeWithSources(packageFqName, files, moduleInfo));
val moduleInfo = info.moduleInfo
if (moduleInfo is ModuleSourceInfo) {
result.addAll(getLightClassesForPackageFacadeWithSources(packageFqName, files, moduleInfo))
}
else {
result.addAll(getLightClassesForDecompiledFacadeFiles(files));
result.addAll(getLightClassesForDecompiledFacadeFiles(files))
}
}
return result;
return result
}
@NotNull
private List<PsiClass> getLightClassesForPackageFacadeWithSources(
@NotNull FqName packageFqName,
@NotNull List<JetFile> facadeFiles,
@NotNull IdeaModuleInfo moduleInfo
) {
KotlinLightClassForFacade lightClassForFacade =
KotlinLightClassForFacade.Factory.createForPackageFacade(psiManager, packageFqName, moduleInfo.contentScope(), facadeFiles);
return getLightClassesForFacadeWithFiles(lightClassForFacade, facadeFiles);
private fun getLightClassesForPackageFacadeWithSources(
packageFqName: FqName,
facadeFiles: List<JetFile>,
moduleInfo: IdeaModuleInfo): List<PsiClass> {
val lightClassForFacade = KotlinLightClassForFacade.createForPackageFacade(psiManager, packageFqName, moduleInfo.contentScope(), facadeFiles)
return getLightClassesForFacadeWithFiles(lightClassForFacade, facadeFiles)
}
@NotNull
private List<PsiClass> getLightClassesForFacadeWithFiles(
@Nullable KotlinLightClassForFacade lightClassForFacade,
@NotNull List<JetFile> facadeFiles
) {
if (lightClassForFacade == null) return emptyList();
private fun getLightClassesForFacadeWithFiles(
lightClassForFacade: KotlinLightClassForFacade?,
facadeFiles: List<JetFile>): List<PsiClass> {
if (lightClassForFacade == null) return emptyList()
List<PsiClass> lightClasses = new ArrayList<PsiClass>();
lightClasses.add(lightClassForFacade);
val lightClasses = ArrayList<PsiClass>()
lightClasses.add(lightClassForFacade)
if (facadeFiles.size() > 1) {
for (JetFile file : facadeFiles) {
lightClasses.add(new FakeLightClassForFileOfPackage(psiManager, lightClassForFacade, file));
for (file in facadeFiles) {
lightClasses.add(FakeLightClassForFileOfPackage(psiManager, lightClassForFacade, file))
}
}
return lightClasses;
return lightClasses
}
@NotNull
@Override
public Collection<PsiClass> getFacadeClasses(@NotNull FqName facadeFqName, @NotNull GlobalSearchScope scope) {
List<PsiClass> result = new ArrayList<PsiClass>();
List<KotlinLightFacadeClassInfo> facadeClassesInfos = findFacadeClassesInfos(facadeFqName, scope);
for (KotlinLightFacadeClassInfo info : facadeClassesInfos) {
List<JetFile> files = PackagePartClassUtils.getFilesWithCallables(info.getFiles());
if (files.isEmpty()) continue;
override fun getFacadeClasses(facadeFqName: FqName, scope: GlobalSearchScope): Collection<PsiClass> {
val result = ArrayList<PsiClass>()
val facadeClassesInfos = findFacadeClassesInfos(facadeFqName, scope)
for (info in facadeClassesInfos) {
val files = PackagePartClassUtils.getFilesWithCallables(info.files)
if (files.isEmpty()) continue
IdeaModuleInfo moduleInfo = info.getModuleInfo();
if (moduleInfo instanceof ModuleSourceInfo) {
result.addAll(getLightClassesForStaticFacadeWithSources(facadeFqName, files, moduleInfo));
val moduleInfo = info.moduleInfo
if (moduleInfo is ModuleSourceInfo) {
result.addAll(getLightClassesForStaticFacadeWithSources(facadeFqName, files, moduleInfo))
}
else {
result.addAll(getLightClassesForDecompiledFacadeFiles(files));
result.addAll(getLightClassesForDecompiledFacadeFiles(files))
}
}
return result;
return result
}
private List<PsiClass> getLightClassesForStaticFacadeWithSources(
@NotNull FqName facadeFqName,
@NotNull List<JetFile> facadeFiles,
@NotNull IdeaModuleInfo moduleInfo
) {
KotlinLightClassForFacade lightClassForFacade = KotlinLightClassForFacade.Factory.createForFacade(
psiManager, facadeFqName, moduleInfo.contentScope(), facadeFiles);
return getLightClassesForFacadeWithFiles(lightClassForFacade, facadeFiles);
private fun getLightClassesForStaticFacadeWithSources(
facadeFqName: FqName,
facadeFiles: List<JetFile>,
moduleInfo: IdeaModuleInfo): List<PsiClass> {
val lightClassForFacade = KotlinLightClassForFacade.createForFacade(
psiManager, facadeFqName, moduleInfo.contentScope(), facadeFiles)
return getLightClassesForFacadeWithFiles(lightClassForFacade, facadeFiles)
}
@NotNull
@Override
public Collection<JetFile> findFilesForFacade(@NotNull FqName facadeFqName, @NotNull GlobalSearchScope scope) {
return StaticFacadeIndexUtil.findFilesForStaticFacade(facadeFqName, kotlinSourcesAndLibraries(scope, project), project);
override fun findFilesForFacade(facadeFqName: FqName, scope: GlobalSearchScope): Collection<JetFile> {
return StaticFacadeIndexUtil.findFilesForStaticFacade(facadeFqName, kotlinSourcesAndLibraries(scope, project), project)
}
@NotNull
private List<KotlinLightFacadeClassInfo> findFacadeClassesInfos(FqName facadeFqName, GlobalSearchScope scope) {
Collection<JetFile> facadeFiles = findFilesForFacade(facadeFqName, scope);
return groupFilesIntoFacadeLightClassesByModuleInfo(facadeFiles);
private fun findFacadeClassesInfos(facadeFqName: FqName, scope: GlobalSearchScope): List<KotlinLightFacadeClassInfo> {
val facadeFiles = findFilesForFacade(facadeFqName, scope)
return groupFilesIntoFacadeLightClassesByModuleInfo(facadeFiles)
}
@NotNull
private static List<KotlinLightFacadeClassInfo> groupFilesIntoFacadeLightClassesByModuleInfo(Collection<JetFile> facadeFiles) {
Map<IdeaModuleInfo, List<JetFile>> filesByInfo = KotlinPackage.groupByTo(
facadeFiles,
new LinkedHashMap<IdeaModuleInfo, List<JetFile>>(),
new Function1<JetFile, IdeaModuleInfo>() {
@Override
public IdeaModuleInfo invoke(JetFile file) {
return ResolvePackage.getModuleInfo(file);
}
});
List<KotlinLightFacadeClassInfo> result = new ArrayList<KotlinLightFacadeClassInfo>();
for (Map.Entry<IdeaModuleInfo, List<JetFile>> entry : filesByInfo.entrySet()) {
result.add(new KotlinLightFacadeClassInfo(entry.getValue(), entry.getKey()));
}
return result;
}
@Nullable
@Override
public ClassDescriptor resolveClassToDescriptor(@NotNull JetClassOrObject classOrObject) {
override fun resolveClassToDescriptor(classOrObject: JetClassOrObject): ClassDescriptor? {
try {
return (ClassDescriptor) ResolvePackage.resolveToDescriptor(classOrObject);
return classOrObject.resolveToDescriptor() as ClassDescriptor
}
catch (NoDescriptorForDeclarationException e) {
return null;
catch (e: NoDescriptorForDeclarationException) {
return null
}
}
@NotNull
private static List<PsiClass> getLightClassesForDecompiledFacadeFiles(@NotNull List<JetFile> filesWithCallables) {
List<PsiClass> lightClasses = new ArrayList<PsiClass>();
for (JetFile file : filesWithCallables) {
if (file.isCompiled()) {
lightClasses.add(createLightClassForDecompiledKotlinFile(file));
}
}
return lightClasses;
private fun findPackageClassesInfos(
fqName: FqName, wholeScope: GlobalSearchScope): List<KotlinLightFacadeClassInfo> {
val allFiles = findFilesForPackage(fqName, wholeScope)
return groupFilesIntoFacadeLightClassesByModuleInfo(allFiles)
}
@NotNull
private List<KotlinLightFacadeClassInfo> findPackageClassesInfos(
@NotNull FqName fqName, @NotNull GlobalSearchScope wholeScope
) {
Collection<JetFile> allFiles = findFilesForPackage(fqName, wholeScope);
return groupFilesIntoFacadeLightClassesByModuleInfo(allFiles);
}
private class KotlinLightFacadeClassInfo(public val files: Collection<JetFile>, public val moduleInfo: IdeaModuleInfo)
private static final class KotlinLightFacadeClassInfo {
private final Collection<JetFile> files;
private final IdeaModuleInfo moduleInfo;
private class CachedJavaStub(public var modificationStamp: Long, public var javaFileStub: PsiJavaFileStubImpl)
public KotlinLightFacadeClassInfo(@NotNull Collection<JetFile> files, @NotNull IdeaModuleInfo moduleInfo) {
this.files = files;
this.moduleInfo = moduleInfo;
}
companion object {
@NotNull
public Collection<JetFile> getFiles() {
return files;
}
private val LOG = Logger.getInstance(javaClass<IDELightClassGenerationSupport>())
@NotNull
public IdeaModuleInfo getModuleInfo() {
return moduleInfo;
}
}
private fun forceResolvePackageDeclarations(files: Collection<JetFile>, session: KotlinCodeAnalyzer) {
for (file in files) {
// SCRIPT: not supported
if (file.isScript) continue
@Nullable
private static KotlinLightClassForDecompiledDeclaration createLightClassForDecompiledKotlinFile(@NotNull JetFile file) {
VirtualFile virtualFile = file.getVirtualFile();
if (virtualFile == null) {
return null;
}
val packageFqName = file.packageFqName
JetClassOrObject classOrObject = singleOrNull(filterIsInstance(file.getDeclarations(), JetClassOrObject.class));
ClsClassImpl javaClsClass = createClsJavaClassFromVirtualFile(file, virtualFile, classOrObject);
if (javaClsClass == null) {
return null;
}
return new KotlinLightClassForDecompiledDeclaration(javaClsClass, classOrObject);
}
@Nullable
private static ClsClassImpl createClsJavaClassFromVirtualFile(
@NotNull final JetFile decompiledKotlinFile,
@NotNull VirtualFile virtualFile,
@Nullable final JetClassOrObject decompiledClassOrObject
) {
final PsiJavaFileStubImpl javaFileStub = getOrCreateJavaFileStub(decompiledKotlinFile, virtualFile);
if (javaFileStub == null) {
return null;
}
PsiManager manager = PsiManager.getInstance(decompiledKotlinFile.getProject());
ClsFileImpl fakeFile = new ClsFileImpl(new ClassFileViewProvider(manager, virtualFile)) {
@NotNull
@Override
public PsiElement getNavigationElement() {
if (decompiledClassOrObject != null) {
return decompiledClassOrObject.getNavigationElement().getContainingFile();
// make sure we create a package descriptor
val packageDescriptor = session.moduleDescriptor.getPackage(packageFqName)
if (packageDescriptor.isEmpty()) {
LOG.warn("No descriptor found for package " + packageFqName + " in file " + file.name + "\n" + file.text)
session.forceResolveAll()
continue
}
return super.getNavigationElement();
for (declaration in file.declarations) {
if (declaration is JetFunction) {
val name = declaration.nameAsSafeName
val functions = packageDescriptor.memberScope.getFunctions(name, NoLookupLocation.FROM_IDE)
for (descriptor in functions) {
ForceResolveUtil.forceResolveAllContents(descriptor)
}
}
else if (declaration is JetProperty) {
val name = declaration.nameAsSafeName
val properties = packageDescriptor.memberScope.getProperties(name, NoLookupLocation.FROM_IDE)
for (descriptor in properties) {
ForceResolveUtil.forceResolveAllContents(descriptor)
}
}
else if (declaration is JetClassOrObject) {
// Do nothing: we are not interested in classes
}
else {
LOG.error("Unsupported declaration kind: " + declaration + " in file " + file.name + "\n" + file.text)
}
}
}
}
private fun getLightClassForDecompiledClassOrObject(decompiledClassOrObject: JetClassOrObject): PsiClass? {
if (decompiledClassOrObject is JetEnumEntry) {
return null
}
val containingJetFile = decompiledClassOrObject.getContainingJetFile()
if (!containingJetFile.isCompiled) {
return null
}
val rootLightClassForDecompiledFile = createLightClassForDecompiledKotlinFile(containingJetFile) ?: return null
return findCorrespondingLightClass(decompiledClassOrObject, rootLightClassForDecompiledFile)
}
private fun findCorrespondingLightClass(
decompiledClassOrObject: JetClassOrObject,
rootLightClassForDecompiledFile: PsiClass): PsiClass {
val relativeFqName = getClassRelativeName(decompiledClassOrObject)
val iterator = relativeFqName.pathSegments().iterator()
val base = iterator.next()
assert(rootLightClassForDecompiledFile.name == base.asString()) { "Light class for file:\n" + decompiledClassOrObject.getContainingJetFile().virtualFile.canonicalPath + "\nwas expected to have name: " + base.asString() + "\n Actual: " + rootLightClassForDecompiledFile.name }
var current = rootLightClassForDecompiledFile
while (iterator.hasNext()) {
val name = iterator.next()
val innerClass = current.findInnerClassByName(name.asString(), false)
assert(innerClass != null) { "Could not find corresponding inner/nested class " + relativeFqName + " in class " + decompiledClassOrObject.fqName + "\n" + "File: " + decompiledClassOrObject.getContainingJetFile().virtualFile.name }
current = innerClass
}
return current
}
private fun getClassRelativeName(decompiledClassOrObject: JetClassOrObject): FqName {
val name = decompiledClassOrObject.nameAsName
assert(name != null)
val parent = PsiTreeUtil.getParentOfType(decompiledClassOrObject, javaClass<JetClassOrObject>(), true)
if (parent == null) {
assert(decompiledClassOrObject.isTopLevel())
return FqName.topLevel(name)
}
return getClassRelativeName(parent).child(name)
}
private fun groupFilesIntoFacadeLightClassesByModuleInfo(facadeFiles: Collection<JetFile>): List<KotlinLightFacadeClassInfo> {
val filesByInfo = KotlinPackage.groupByTo(
facadeFiles,
LinkedHashMap<IdeaModuleInfo, List<JetFile>>(),
object : Function1<JetFile, IdeaModuleInfo> {
override fun invoke(file: JetFile): IdeaModuleInfo {
return file.getModuleInfo()
}
})
val result = ArrayList<KotlinLightFacadeClassInfo>()
for (entry in filesByInfo.entrySet()) {
result.add(KotlinLightFacadeClassInfo(entry.getValue(), entry.getKey()))
}
return result
}
private fun getLightClassesForDecompiledFacadeFiles(filesWithCallables: List<JetFile>): List<PsiClass> {
val lightClasses = ArrayList<PsiClass>()
for (file in filesWithCallables) {
if (file.isCompiled) {
lightClasses.add(createLightClassForDecompiledKotlinFile(file))
}
}
return lightClasses
}
private fun createLightClassForDecompiledKotlinFile(file: JetFile): KotlinLightClassForDecompiledDeclaration? {
val virtualFile = file.virtualFile ?: return null
val classOrObject = singleOrNull<JetClassOrObject>(filterIsInstance<JetClassOrObject>(file.declarations, javaClass<JetClassOrObject>()))
val javaClsClass = createClsJavaClassFromVirtualFile(file, virtualFile, classOrObject) ?: return null
return KotlinLightClassForDecompiledDeclaration(javaClsClass, classOrObject)
}
private fun createClsJavaClassFromVirtualFile(
decompiledKotlinFile: JetFile,
virtualFile: VirtualFile,
decompiledClassOrObject: JetClassOrObject?): ClsClassImpl? {
val javaFileStub = getOrCreateJavaFileStub(decompiledKotlinFile, virtualFile) ?: return null
val manager = PsiManager.getInstance(decompiledKotlinFile.project)
val fakeFile = object : ClsFileImpl(ClassFileViewProvider(manager, virtualFile)) {
override fun getNavigationElement(): PsiElement {
if (decompiledClassOrObject != null) {
return decompiledClassOrObject.navigationElement.containingFile
}
return super.getNavigationElement()
}
override fun getStub(): PsiClassHolderFileStub<PsiFile> {
return javaFileStub
}
override fun getMirror(): PsiElement {
return decompiledKotlinFile
}
}
fakeFile.isPhysical = false
javaFileStub.setPsi(fakeFile)
return single<PsiClass>(fakeFile.classes) as ClsClassImpl
}
private val cachedJavaStubKey = Key.create<CachedJavaStub>("CACHED_JAVA_STUB")
private fun getOrCreateJavaFileStub(
decompiledKotlinFile: JetFile,
virtualFile: VirtualFile): PsiJavaFileStubImpl? {
val cachedJavaStub = decompiledKotlinFile.getUserData(cachedJavaStubKey)
val fileModificationStamp = virtualFile.modificationStamp
if (cachedJavaStub != null && cachedJavaStub.modificationStamp == fileModificationStamp) {
return cachedJavaStub.javaFileStub
}
val stub = createStub(virtualFile) as PsiJavaFileStubImpl?
if (stub != null) {
decompiledKotlinFile.putUserData(cachedJavaStubKey, CachedJavaStub(fileModificationStamp, stub))
}
return stub
}
private fun createStub(file: VirtualFile): PsiJavaFileStub? {
if (file.fileType !== JavaClassFileType.INSTANCE) return null
try {
return ClsFileImpl.buildFileStub(file, file.contentsToByteArray())
}
catch (e: ClsFormatException) {
LOG.debug(e)
}
catch (e: IOException) {
LOG.debug(e)
}
@NotNull
@Override
public PsiClassHolderFileStub getStub() {
return javaFileStub;
}
@Override
public PsiElement getMirror() {
return decompiledKotlinFile;
}
};
fakeFile.setPhysical(false);
javaFileStub.setPsi(fakeFile);
return (ClsClassImpl) single(fakeFile.getClasses());
}
private final static Key<CachedJavaStub> cachedJavaStubKey = Key.create("CACHED_JAVA_STUB");
private static class CachedJavaStub {
public CachedJavaStub(long modificationStamp, @NotNull PsiJavaFileStubImpl javaFileStub) {
this.modificationStamp = modificationStamp;
this.javaFileStub = javaFileStub;
LOG.error("Failed to build java cls class for " + file.canonicalPath!!)
return null
}
public long modificationStamp;
public PsiJavaFileStubImpl javaFileStub;
}
@Nullable
private static PsiJavaFileStubImpl getOrCreateJavaFileStub(
@NotNull JetFile decompiledKotlinFile,
@NotNull VirtualFile virtualFile) {
CachedJavaStub cachedJavaStub = decompiledKotlinFile.getUserData(cachedJavaStubKey);
long fileModificationStamp = virtualFile.getModificationStamp();
if (cachedJavaStub != null && cachedJavaStub.modificationStamp == fileModificationStamp) {
return cachedJavaStub.javaFileStub;
}
PsiJavaFileStubImpl stub = (PsiJavaFileStubImpl) createStub(virtualFile);
if (stub != null) {
decompiledKotlinFile.putUserData(cachedJavaStubKey, new CachedJavaStub(fileModificationStamp, stub));
}
return stub;
}
@Nullable
private static PsiJavaFileStub createStub(@NotNull VirtualFile file) {
if (file.getFileType() != JavaClassFileType.INSTANCE) return null;
try {
return ClsFileImpl.buildFileStub(file, file.contentsToByteArray());
}
catch (ClsFormatException e) {
LOG.debug(e);
}
catch (IOException e) {
LOG.debug(e);
}
LOG.error("Failed to build java cls class for " + file.getCanonicalPath());
return null;
}
}