J2K IDELightClassGenerationSupport: autoconvert
This commit is contained in:
+322
-418
@@ -14,514 +14,418 @@
|
|||||||
* limitations under the License.
|
* 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.ide.highlighter.JavaClassFileType
|
||||||
import com.intellij.openapi.diagnostic.Logger;
|
import com.intellij.openapi.diagnostic.Logger
|
||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.roots.libraries.LibraryUtil;
|
import com.intellij.openapi.roots.libraries.LibraryUtil
|
||||||
import com.intellij.openapi.util.Key;
|
import com.intellij.openapi.util.Key
|
||||||
import com.intellij.openapi.vfs.VirtualFile;
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
import com.intellij.psi.ClassFileViewProvider;
|
import com.intellij.psi.ClassFileViewProvider
|
||||||
import com.intellij.psi.PsiClass;
|
import com.intellij.psi.PsiClass
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.PsiManager;
|
import com.intellij.psi.PsiManager
|
||||||
import com.intellij.psi.impl.compiled.ClsClassImpl;
|
import com.intellij.psi.impl.compiled.ClsClassImpl
|
||||||
import com.intellij.psi.impl.compiled.ClsFileImpl;
|
import com.intellij.psi.impl.compiled.ClsFileImpl
|
||||||
import com.intellij.psi.impl.java.stubs.PsiJavaFileStub;
|
import com.intellij.psi.impl.java.stubs.PsiJavaFileStub
|
||||||
import com.intellij.psi.impl.java.stubs.impl.PsiJavaFileStubImpl;
|
import com.intellij.psi.impl.java.stubs.impl.PsiJavaFileStubImpl
|
||||||
import com.intellij.psi.search.GlobalSearchScope;
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
import com.intellij.psi.stubs.PsiClassHolderFileStub;
|
import com.intellij.psi.stubs.PsiClassHolderFileStub
|
||||||
import com.intellij.psi.util.PsiTreeUtil;
|
import com.intellij.psi.util.PsiTreeUtil
|
||||||
import com.intellij.util.cls.ClsFormatException;
|
import com.intellij.util.cls.ClsFormatException
|
||||||
import kotlin.KotlinPackage;
|
import kotlin.KotlinPackage
|
||||||
import kotlin.jvm.functions.Function1;
|
import org.jetbrains.kotlin.asJava.*
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.kotlin.idea.decompiler.navigation.JetSourceNavigationHelper
|
||||||
import org.jetbrains.kotlin.asJava.*;
|
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||||
import org.jetbrains.kotlin.descriptors.*;
|
import org.jetbrains.kotlin.idea.stubindex.JetFullClassNameIndex
|
||||||
import org.jetbrains.kotlin.idea.decompiler.navigation.JetSourceNavigationHelper;
|
import org.jetbrains.kotlin.idea.stubindex.JetTopLevelClassByPackageIndex
|
||||||
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade;
|
import org.jetbrains.kotlin.idea.stubindex.PackageIndexUtil
|
||||||
import org.jetbrains.kotlin.idea.stubindex.JetFullClassNameIndex;
|
import org.jetbrains.kotlin.idea.stubindex.StaticFacadeIndexUtil
|
||||||
import org.jetbrains.kotlin.idea.stubindex.JetTopLevelClassByPackageIndex;
|
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
|
||||||
import org.jetbrains.kotlin.idea.stubindex.PackageIndexUtil;
|
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||||
import org.jetbrains.kotlin.idea.stubindex.StaticFacadeIndexUtil;
|
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils
|
||||||
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil;
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils;
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.name.FqName;
|
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||||
import org.jetbrains.kotlin.name.Name;
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.psi.*;
|
import org.jetbrains.kotlin.resolve.lazy.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.PsiUtilPackage;
|
import org.jetbrains.kotlin.resolve.scopes.JetScope
|
||||||
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.io.IOException
|
||||||
import java.util.*;
|
import java.util.*
|
||||||
|
|
||||||
import static kotlin.KotlinPackage.*;
|
import kotlin.KotlinPackage.*
|
||||||
import static org.jetbrains.kotlin.idea.stubindex.JetSourceFilterScope.kotlinSourceAndClassFiles;
|
import org.jetbrains.kotlin.idea.stubindex.JetSourceFilterScope.kotlinSourceAndClassFiles
|
||||||
import static org.jetbrains.kotlin.idea.stubindex.JetSourceFilterScope.kotlinSourcesAndLibraries;
|
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;
|
init {
|
||||||
|
this.scopeFileComparator = JavaElementFinder.byClasspathComparator(GlobalSearchScope.allScope(project))
|
||||||
private final Comparator<PsiElement> scopeFileComparator;
|
this.psiManager = PsiManager.getInstance(project)
|
||||||
private final PsiManager psiManager;
|
|
||||||
|
|
||||||
public IDELightClassGenerationSupport(@NotNull Project project) {
|
|
||||||
this.project = project;
|
|
||||||
this.scopeFileComparator = JavaElementFinder.byClasspathComparator(GlobalSearchScope.allScope(project));
|
|
||||||
this.psiManager = PsiManager.getInstance(project);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@NotNull
|
override fun getContextForPackage(files: Collection<JetFile>): LightClassConstructionContext {
|
||||||
@Override
|
assert(!files.isEmpty(), "No files in package")
|
||||||
public LightClassConstructionContext getContextForPackage(@NotNull Collection<JetFile> files) {
|
|
||||||
assert !files.isEmpty() : "No files in package";
|
|
||||||
|
|
||||||
return getContextForFiles(files);
|
return getContextForFiles(files)
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
private fun getContextForFiles(files: Collection<JetFile>): LightClassConstructionContext {
|
||||||
private LightClassConstructionContext getContextForFiles(@NotNull Collection<JetFile> files) {
|
val sortedFiles = ArrayList(files)
|
||||||
List<JetFile> sortedFiles = new ArrayList<JetFile>(files);
|
Collections.sort(sortedFiles, scopeFileComparator)
|
||||||
Collections.sort(sortedFiles, scopeFileComparator);
|
|
||||||
|
|
||||||
JetFile file = sortedFiles.get(0);
|
val file = sortedFiles.get(0)
|
||||||
ResolveSession resolveSession = ResolvePackage.getResolutionFacade(file).getFrontendService(ResolveSession.class);
|
val resolveSession = file.getResolutionFacade().getFrontendService(javaClass<ResolveSession>())
|
||||||
forceResolvePackageDeclarations(files, resolveSession);
|
forceResolvePackageDeclarations(files, resolveSession)
|
||||||
return new LightClassConstructionContext(resolveSession.getBindingContext(), resolveSession.getModuleDescriptor());
|
return LightClassConstructionContext(resolveSession.bindingContext, resolveSession.getModuleDescriptor())
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
override fun getContextForClassOrObject(classOrObject: JetClassOrObject): LightClassConstructionContext {
|
||||||
@Override
|
val resolutionFacade = classOrObject.getResolutionFacade()
|
||||||
public LightClassConstructionContext getContextForClassOrObject(@NotNull JetClassOrObject classOrObject) {
|
|
||||||
ResolutionFacade resolutionFacade = ResolvePackage.getResolutionFacade(classOrObject);
|
|
||||||
|
|
||||||
ModuleDescriptor moduleDescriptor = resolutionFacade.getModuleDescriptor();
|
val moduleDescriptor = resolutionFacade.moduleDescriptor
|
||||||
BindingContext bindingContext = resolutionFacade.analyze(classOrObject, BodyResolveMode.FULL);
|
val bindingContext = resolutionFacade.analyze(classOrObject, BodyResolveMode.FULL)
|
||||||
if (classOrObject.isLocal()) {
|
if (classOrObject.isLocal()) {
|
||||||
ClassDescriptor descriptor = bindingContext.get(BindingContext.CLASS, classOrObject);
|
val descriptor = bindingContext.get(BindingContext.CLASS, classOrObject)
|
||||||
|
|
||||||
|
|
||||||
if (descriptor == null) {
|
if (descriptor == null) {
|
||||||
LOG.warn("No class descriptor in context for class: " + PsiUtilPackage.getElementTextWithContext(classOrObject));
|
LOG.warn("No class descriptor in context for class: " + classOrObject.getElementTextWithContext())
|
||||||
return new LightClassConstructionContext(bindingContext, moduleDescriptor);
|
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));
|
ForceResolveUtil.forceResolveAllContents(resolutionFacade.resolveToDescriptor(classOrObject))
|
||||||
return new LightClassConstructionContext(bindingContext, moduleDescriptor);
|
return LightClassConstructionContext(bindingContext, moduleDescriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
override fun getContextForFacade(files: Collection<JetFile>): LightClassConstructionContext {
|
||||||
@Override
|
assert(!files.isEmpty(), "No files in facade")
|
||||||
public LightClassConstructionContext getContextForFacade(@NotNull Collection<JetFile> files) {
|
|
||||||
assert !files.isEmpty() : "No files in facade";
|
|
||||||
|
|
||||||
return getContextForFiles(files);
|
return getContextForFiles(files)
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void forceResolvePackageDeclarations(@NotNull Collection<JetFile> files, @NotNull KotlinCodeAnalyzer session) {
|
override fun findClassOrObjectDeclarations(fqName: FqName, searchScope: GlobalSearchScope): Collection<JetClassOrObject> {
|
||||||
for (JetFile file : files) {
|
return JetFullClassNameIndex.getInstance().get(fqName.asString(), project, kotlinSourceAndClassFiles(searchScope, project))
|
||||||
// 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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
override fun findFilesForPackage(fqName: FqName, searchScope: GlobalSearchScope): Collection<JetFile> {
|
||||||
@Override
|
return PackageIndexUtil.findFilesWithExactPackage(fqName, kotlinSourceAndClassFiles(searchScope, project), project)
|
||||||
public Collection<JetClassOrObject> findClassOrObjectDeclarations(@NotNull FqName fqName, @NotNull GlobalSearchScope searchScope) {
|
|
||||||
return JetFullClassNameIndex.getInstance().get(fqName.asString(), project, kotlinSourceAndClassFiles(searchScope, project));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
override fun findClassOrObjectDeclarationsInPackage(
|
||||||
@Override
|
packageFqName: FqName, searchScope: GlobalSearchScope): Collection<JetClassOrObject> {
|
||||||
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
|
|
||||||
) {
|
|
||||||
return JetTopLevelClassByPackageIndex.getInstance().get(
|
return JetTopLevelClassByPackageIndex.getInstance().get(
|
||||||
packageFqName.asString(), project, kotlinSourceAndClassFiles(searchScope, project)
|
packageFqName.asString(), project, kotlinSourceAndClassFiles(searchScope, project))
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
override fun packageExists(fqName: FqName, scope: GlobalSearchScope): Boolean {
|
||||||
public boolean packageExists(@NotNull FqName fqName, @NotNull GlobalSearchScope scope) {
|
return PackageIndexUtil.packageExists(fqName, kotlinSourceAndClassFiles(scope, project), project)
|
||||||
return PackageIndexUtil.packageExists(fqName, kotlinSourceAndClassFiles(scope, project), project);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
override fun getSubPackages(fqn: FqName, scope: GlobalSearchScope): Collection<FqName> {
|
||||||
@Override
|
return PackageIndexUtil.getSubPackageFqNames(fqn, kotlinSourceAndClassFiles(scope, project), project, JetScope.ALL_NAME_FILTER)
|
||||||
public Collection<FqName> getSubPackages(@NotNull FqName fqn, @NotNull GlobalSearchScope scope) {
|
|
||||||
return PackageIndexUtil.getSubPackageFqNames(fqn, kotlinSourceAndClassFiles(scope, project), project, JetScope.ALL_NAME_FILTER);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
override fun getPsiClass(classOrObject: JetClassOrObject): PsiClass? {
|
||||||
@Override
|
val virtualFile = classOrObject.containingFile.virtualFile
|
||||||
public PsiClass getPsiClass(@NotNull JetClassOrObject classOrObject) {
|
if (virtualFile != null && LibraryUtil.findLibraryEntry(virtualFile, classOrObject.project) != null) {
|
||||||
VirtualFile virtualFile = classOrObject.getContainingFile().getVirtualFile();
|
|
||||||
if (virtualFile != null && LibraryUtil.findLibraryEntry(virtualFile, classOrObject.getProject()) != null) {
|
|
||||||
if (ProjectRootsUtil.isLibraryClassFile(project, virtualFile)) {
|
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
|
override fun getPackageClasses(packageFqName: FqName, scope: GlobalSearchScope): Collection<PsiClass> {
|
||||||
private static PsiClass getLightClassForDecompiledClassOrObject(@NotNull JetClassOrObject decompiledClassOrObject) {
|
val result = ArrayList<PsiClass>()
|
||||||
if (decompiledClassOrObject instanceof JetEnumEntry) {
|
val packageClassesInfos = findPackageClassesInfos(packageFqName, scope)
|
||||||
return null;
|
for (info in packageClassesInfos) {
|
||||||
}
|
val files = PackagePartClassUtils.getFilesWithCallables(info.files)
|
||||||
JetFile containingJetFile = decompiledClassOrObject.getContainingJetFile();
|
if (files.isEmpty()) continue
|
||||||
if (!containingJetFile.isCompiled()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
PsiClass rootLightClassForDecompiledFile = createLightClassForDecompiledKotlinFile(containingJetFile);
|
|
||||||
if (rootLightClassForDecompiledFile == null) return null;
|
|
||||||
|
|
||||||
return findCorrespondingLightClass(decompiledClassOrObject, rootLightClassForDecompiledFile);
|
val moduleInfo = info.moduleInfo
|
||||||
}
|
if (moduleInfo is ModuleSourceInfo) {
|
||||||
|
result.addAll(getLightClassesForPackageFacadeWithSources(packageFqName, files, moduleInfo))
|
||||||
@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));
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
result.addAll(getLightClassesForDecompiledFacadeFiles(files));
|
result.addAll(getLightClassesForDecompiledFacadeFiles(files))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
private fun getLightClassesForPackageFacadeWithSources(
|
||||||
private List<PsiClass> getLightClassesForPackageFacadeWithSources(
|
packageFqName: FqName,
|
||||||
@NotNull FqName packageFqName,
|
facadeFiles: List<JetFile>,
|
||||||
@NotNull List<JetFile> facadeFiles,
|
moduleInfo: IdeaModuleInfo): List<PsiClass> {
|
||||||
@NotNull IdeaModuleInfo moduleInfo
|
val lightClassForFacade = KotlinLightClassForFacade.createForPackageFacade(psiManager, packageFqName, moduleInfo.contentScope(), facadeFiles)
|
||||||
) {
|
return getLightClassesForFacadeWithFiles(lightClassForFacade, facadeFiles)
|
||||||
KotlinLightClassForFacade lightClassForFacade =
|
|
||||||
KotlinLightClassForFacade.Factory.createForPackageFacade(psiManager, packageFqName, moduleInfo.contentScope(), facadeFiles);
|
|
||||||
return getLightClassesForFacadeWithFiles(lightClassForFacade, facadeFiles);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
private fun getLightClassesForFacadeWithFiles(
|
||||||
private List<PsiClass> getLightClassesForFacadeWithFiles(
|
lightClassForFacade: KotlinLightClassForFacade?,
|
||||||
@Nullable KotlinLightClassForFacade lightClassForFacade,
|
facadeFiles: List<JetFile>): List<PsiClass> {
|
||||||
@NotNull List<JetFile> facadeFiles
|
if (lightClassForFacade == null) return emptyList()
|
||||||
) {
|
|
||||||
if (lightClassForFacade == null) return emptyList();
|
|
||||||
|
|
||||||
List<PsiClass> lightClasses = new ArrayList<PsiClass>();
|
val lightClasses = ArrayList<PsiClass>()
|
||||||
lightClasses.add(lightClassForFacade);
|
lightClasses.add(lightClassForFacade)
|
||||||
if (facadeFiles.size() > 1) {
|
if (facadeFiles.size() > 1) {
|
||||||
for (JetFile file : facadeFiles) {
|
for (file in facadeFiles) {
|
||||||
lightClasses.add(new FakeLightClassForFileOfPackage(psiManager, lightClassForFacade, file));
|
lightClasses.add(FakeLightClassForFileOfPackage(psiManager, lightClassForFacade, file))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return lightClasses;
|
return lightClasses
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
override fun getFacadeClasses(facadeFqName: FqName, scope: GlobalSearchScope): Collection<PsiClass> {
|
||||||
@Override
|
val result = ArrayList<PsiClass>()
|
||||||
public Collection<PsiClass> getFacadeClasses(@NotNull FqName facadeFqName, @NotNull GlobalSearchScope scope) {
|
val facadeClassesInfos = findFacadeClassesInfos(facadeFqName, scope)
|
||||||
List<PsiClass> result = new ArrayList<PsiClass>();
|
for (info in facadeClassesInfos) {
|
||||||
List<KotlinLightFacadeClassInfo> facadeClassesInfos = findFacadeClassesInfos(facadeFqName, scope);
|
val files = PackagePartClassUtils.getFilesWithCallables(info.files)
|
||||||
for (KotlinLightFacadeClassInfo info : facadeClassesInfos) {
|
if (files.isEmpty()) continue
|
||||||
List<JetFile> files = PackagePartClassUtils.getFilesWithCallables(info.getFiles());
|
|
||||||
if (files.isEmpty()) continue;
|
|
||||||
|
|
||||||
IdeaModuleInfo moduleInfo = info.getModuleInfo();
|
val moduleInfo = info.moduleInfo
|
||||||
if (moduleInfo instanceof ModuleSourceInfo) {
|
if (moduleInfo is ModuleSourceInfo) {
|
||||||
result.addAll(getLightClassesForStaticFacadeWithSources(facadeFqName, files, moduleInfo));
|
result.addAll(getLightClassesForStaticFacadeWithSources(facadeFqName, files, moduleInfo))
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
result.addAll(getLightClassesForDecompiledFacadeFiles(files));
|
result.addAll(getLightClassesForDecompiledFacadeFiles(files))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<PsiClass> getLightClassesForStaticFacadeWithSources(
|
private fun getLightClassesForStaticFacadeWithSources(
|
||||||
@NotNull FqName facadeFqName,
|
facadeFqName: FqName,
|
||||||
@NotNull List<JetFile> facadeFiles,
|
facadeFiles: List<JetFile>,
|
||||||
@NotNull IdeaModuleInfo moduleInfo
|
moduleInfo: IdeaModuleInfo): List<PsiClass> {
|
||||||
) {
|
val lightClassForFacade = KotlinLightClassForFacade.createForFacade(
|
||||||
KotlinLightClassForFacade lightClassForFacade = KotlinLightClassForFacade.Factory.createForFacade(
|
psiManager, facadeFqName, moduleInfo.contentScope(), facadeFiles)
|
||||||
psiManager, facadeFqName, moduleInfo.contentScope(), facadeFiles);
|
return getLightClassesForFacadeWithFiles(lightClassForFacade, facadeFiles)
|
||||||
return getLightClassesForFacadeWithFiles(lightClassForFacade, facadeFiles);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
override fun findFilesForFacade(facadeFqName: FqName, scope: GlobalSearchScope): Collection<JetFile> {
|
||||||
@Override
|
return StaticFacadeIndexUtil.findFilesForStaticFacade(facadeFqName, kotlinSourcesAndLibraries(scope, project), project)
|
||||||
public Collection<JetFile> findFilesForFacade(@NotNull FqName facadeFqName, @NotNull GlobalSearchScope scope) {
|
|
||||||
return StaticFacadeIndexUtil.findFilesForStaticFacade(facadeFqName, kotlinSourcesAndLibraries(scope, project), project);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
private fun findFacadeClassesInfos(facadeFqName: FqName, scope: GlobalSearchScope): List<KotlinLightFacadeClassInfo> {
|
||||||
private List<KotlinLightFacadeClassInfo> findFacadeClassesInfos(FqName facadeFqName, GlobalSearchScope scope) {
|
val facadeFiles = findFilesForFacade(facadeFqName, scope)
|
||||||
Collection<JetFile> facadeFiles = findFilesForFacade(facadeFqName, scope);
|
return groupFilesIntoFacadeLightClassesByModuleInfo(facadeFiles)
|
||||||
return groupFilesIntoFacadeLightClassesByModuleInfo(facadeFiles);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
override fun resolveClassToDescriptor(classOrObject: JetClassOrObject): ClassDescriptor? {
|
||||||
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) {
|
|
||||||
try {
|
try {
|
||||||
return (ClassDescriptor) ResolvePackage.resolveToDescriptor(classOrObject);
|
return classOrObject.resolveToDescriptor() as ClassDescriptor
|
||||||
}
|
}
|
||||||
catch (NoDescriptorForDeclarationException e) {
|
catch (e: NoDescriptorForDeclarationException) {
|
||||||
return null;
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
private fun findPackageClassesInfos(
|
||||||
private static List<PsiClass> getLightClassesForDecompiledFacadeFiles(@NotNull List<JetFile> filesWithCallables) {
|
fqName: FqName, wholeScope: GlobalSearchScope): List<KotlinLightFacadeClassInfo> {
|
||||||
List<PsiClass> lightClasses = new ArrayList<PsiClass>();
|
val allFiles = findFilesForPackage(fqName, wholeScope)
|
||||||
for (JetFile file : filesWithCallables) {
|
return groupFilesIntoFacadeLightClassesByModuleInfo(allFiles)
|
||||||
if (file.isCompiled()) {
|
|
||||||
lightClasses.add(createLightClassForDecompiledKotlinFile(file));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return lightClasses;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
private class KotlinLightFacadeClassInfo(public val files: Collection<JetFile>, public val moduleInfo: IdeaModuleInfo)
|
||||||
private List<KotlinLightFacadeClassInfo> findPackageClassesInfos(
|
|
||||||
@NotNull FqName fqName, @NotNull GlobalSearchScope wholeScope
|
|
||||||
) {
|
|
||||||
Collection<JetFile> allFiles = findFilesForPackage(fqName, wholeScope);
|
|
||||||
return groupFilesIntoFacadeLightClassesByModuleInfo(allFiles);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class KotlinLightFacadeClassInfo {
|
private class CachedJavaStub(public var modificationStamp: Long, public var javaFileStub: PsiJavaFileStubImpl)
|
||||||
private final Collection<JetFile> files;
|
|
||||||
private final IdeaModuleInfo moduleInfo;
|
|
||||||
|
|
||||||
public KotlinLightFacadeClassInfo(@NotNull Collection<JetFile> files, @NotNull IdeaModuleInfo moduleInfo) {
|
companion object {
|
||||||
this.files = files;
|
|
||||||
this.moduleInfo = moduleInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
private val LOG = Logger.getInstance(javaClass<IDELightClassGenerationSupport>())
|
||||||
public Collection<JetFile> getFiles() {
|
|
||||||
return files;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
private fun forceResolvePackageDeclarations(files: Collection<JetFile>, session: KotlinCodeAnalyzer) {
|
||||||
public IdeaModuleInfo getModuleInfo() {
|
for (file in files) {
|
||||||
return moduleInfo;
|
// SCRIPT: not supported
|
||||||
}
|
if (file.isScript) continue
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
val packageFqName = file.packageFqName
|
||||||
private static KotlinLightClassForDecompiledDeclaration createLightClassForDecompiledKotlinFile(@NotNull JetFile file) {
|
|
||||||
VirtualFile virtualFile = file.getVirtualFile();
|
|
||||||
if (virtualFile == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
JetClassOrObject classOrObject = singleOrNull(filterIsInstance(file.getDeclarations(), JetClassOrObject.class));
|
// make sure we create a package descriptor
|
||||||
|
val packageDescriptor = session.moduleDescriptor.getPackage(packageFqName)
|
||||||
ClsClassImpl javaClsClass = createClsJavaClassFromVirtualFile(file, virtualFile, classOrObject);
|
if (packageDescriptor.isEmpty()) {
|
||||||
if (javaClsClass == null) {
|
LOG.warn("No descriptor found for package " + packageFqName + " in file " + file.name + "\n" + file.text)
|
||||||
return null;
|
session.forceResolveAll()
|
||||||
}
|
continue
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
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
|
LOG.error("Failed to build java cls class for " + file.canonicalPath!!)
|
||||||
@Override
|
return null
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user