Add support of light classes for local class/object declarations

This commit is contained in:
Alexey Sedunov
2013-11-28 17:24:55 +04:00
parent 594c966c44
commit 6913f42a97
20 changed files with 356 additions and 85 deletions
@@ -1,4 +1,8 @@
<root>
<item
name='com.intellij.psi.util.CachedValueProvider.Result com.intellij.psi.util.CachedValueProvider.Result&lt;T&gt; create(T, java.lang.Object...)'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item
name='com.intellij.psi.util.CachedValuesManager com.intellij.psi.util.CachedValue&lt;T&gt; createCachedValue(com.intellij.psi.util.CachedValueProvider&lt;T&gt;, boolean)'>
<annotation name='org.jetbrains.annotations.NotNull'/>
@@ -234,7 +234,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
boolean isLocalOrAnonymousClass = isObjectLiteral ||
!(parentDescriptor instanceof NamespaceDescriptor || parentDescriptor instanceof ClassDescriptor);
if (isLocalOrAnonymousClass) {
// Do not emit enclosing method in "light-classes mode" since currently we genenerate local light classes as if they're top level
if (isLocalOrAnonymousClass && getState().getClassBuilderMode() != ClassBuilderMode.LIGHT_CLASSES) {
String outerClassName = getOuterClassName(descriptor, typeMapper);
FunctionDescriptor function = DescriptorUtils.getParentOfType(descriptor, FunctionDescriptor.class);
@@ -78,14 +78,15 @@ public class MemberCodegen extends ParentCodegenAwareImpl {
public void genClassOrObject(CodegenContext parentContext, JetClassOrObject aClass) {
ClassDescriptor descriptor = state.getBindingContext().get(BindingContext.CLASS, aClass);
if (descriptor == null || ErrorUtils.isError(descriptor) || descriptor.getName().equals(SpecialNames.NO_NAME_PROVIDED)) {
if (state.getClassBuilderMode() != ClassBuilderMode.LIGHT_CLASSES) {
throw new IllegalStateException(
"Generating bad descriptor in ClassBuilderMode = " + state.getClassBuilderMode() + ": " + descriptor);
}
if (descriptor == null || ErrorUtils.isError(descriptor)) {
badDescriptor(descriptor);
return;
}
if (descriptor.getName().equals(SpecialNames.NO_NAME_PROVIDED)) {
badDescriptor(descriptor);
}
ClassBuilder classBuilder = state.getFactory().forClassImplementation(descriptor, aClass.getContainingFile());
ClassContext classContext = parentContext.intoClass(descriptor, OwnerKind.IMPLEMENTATION, state);
new ImplementationBodyCodegen(aClass, classContext, classBuilder, state, this).generate();
@@ -98,4 +99,11 @@ public class MemberCodegen extends ParentCodegenAwareImpl {
traitBuilder.done();
}
}
private void badDescriptor(ClassDescriptor descriptor) {
if (state.getClassBuilderMode() != ClassBuilderMode.LIGHT_CLASSES) {
throw new IllegalStateException(
"Generating bad descriptor in ClassBuilderMode = " + state.getClassBuilderMode() + ": " + descriptor);
}
}
}
@@ -45,6 +45,7 @@ public class CliJetFilesProvider extends JetFilesProvider {
return allFiles;
}
@NotNull
@Override
public List<JetFile> allInScope(@NotNull GlobalSearchScope scope) {
List<JetFile> answer = new ArrayList<JetFile>();
@@ -82,10 +82,20 @@ public class CliLightClassGenerationSupport extends LightClassGenerationSupport
trace = null;
}
private LightClassConstructionContext analyzeRelevantCode() {
return new LightClassConstructionContext(getTrace().getBindingContext(), null);
}
@NotNull
@Override
public LightClassConstructionContext analyzeRelevantCode(@NotNull Collection<JetFile> files) {
return new LightClassConstructionContext(getTrace().getBindingContext(), null);
return analyzeRelevantCode();
}
@NotNull
@Override
public LightClassConstructionContext analyzeRelevantCode(@NotNull JetClassOrObject classOrObject) {
return analyzeRelevantCode();
}
@NotNull
@@ -45,6 +45,7 @@ public abstract class JetFilesProvider {
}
public abstract Function<JetFile, Collection<JetFile>> sampleToAllFilesInModule();
@NotNull
public abstract Collection<JetFile> allInScope(@NotNull GlobalSearchScope scope);
public abstract boolean isFileInScope(@NotNull JetFile file, @NotNull GlobalSearchScope scope);
@@ -570,10 +570,6 @@ public class JetPsiUtil {
return statements.isEmpty() ? null : statements.get(statements.size() - 1);
}
public static boolean isLocalClass(@NotNull JetClassOrObject classOrObject) {
return getOutermostClassOrObject(classOrObject) == null;
}
public static boolean isTrait(@NotNull JetClassOrObject classOrObject) {
return classOrObject instanceof JetClass && ((JetClass) classOrObject).isTrait();
}
@@ -595,7 +591,7 @@ public class JetPsiUtil {
}
if (!(parent instanceof JetClassBody)) {
// It is a local class, no legitimate outer
return null;
return current;
}
current = (JetClassOrObject) parent.getParent();
@@ -0,0 +1,29 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.asJava
import com.intellij.psi.impl.java.stubs.PsiJavaFileStub
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor
import org.jetbrains.jet.lang.resolve.BindingContext
import com.intellij.psi.PsiElement
import org.jetbrains.jet.lang.descriptors.ClassDescriptor
data class GeneratedLightClassData(
val javaFileStub: PsiJavaFileStub,
val jvmInternalName: String,
val descriptor: ClassDescriptor?
)
@@ -37,20 +37,24 @@ import com.intellij.testFramework.LightVirtualFile;
import com.intellij.util.containers.Stack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.asm4.Type;
import org.jetbrains.jet.codegen.CompilationErrorHandler;
import org.jetbrains.jet.codegen.NamespaceCodegen;
import org.jetbrains.jet.codegen.binding.CodegenBinding;
import org.jetbrains.jet.codegen.state.GenerationState;
import org.jetbrains.jet.codegen.state.Progress;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.psi.JetClassOrObject;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetPsiUtil;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.types.lang.InlineUtil;
import java.util.Collection;
import java.util.Collections;
public class KotlinJavaFileStubProvider implements CachedValueProvider<PsiJavaFileStub> {
public class KotlinJavaFileStubProvider implements CachedValueProvider<GeneratedLightClassData> {
@NotNull
public static KotlinJavaFileStubProvider createForPackageClass(
@@ -58,90 +62,131 @@ public class KotlinJavaFileStubProvider implements CachedValueProvider<PsiJavaFi
@NotNull final FqName packageFqName,
@NotNull final GlobalSearchScope searchScope
) {
return new KotlinJavaFileStubProvider(project, new StubGenerationStrategy.NoDeclaredClasses() {
return new KotlinJavaFileStubProvider(
project,
false,
new StubGenerationStrategy.NoDeclaredClasses() {
@NotNull
@Override
public LightClassConstructionContext createLightClassConstructionContext(@NotNull Collection<JetFile> files) {
return LightClassGenerationSupport.getInstance(project).analyzeRelevantCode(files);
}
@NotNull
@Override
public Collection<JetFile> getFiles() {
// Don't memoize this, it can be called again after an out-of-code-block modification occurs,
// and the set of files changes
return LightClassGenerationSupport.getInstance(project).findFilesForPackage(packageFqName, searchScope);
}
@NotNull
@Override
public Collection<JetFile> getFiles() {
// Don't memoize this, it can be called again after an out-of-code-block modification occurs,
// and the set of files changes
return LightClassGenerationSupport.getInstance(project).findFilesForPackage(packageFqName, searchScope);
}
@NotNull
@Override
public FqName getPackageFqName() {
return packageFqName;
}
@NotNull
@Override
public GeneratedLightClassData createStubWithName(PsiJavaFileStub javaFileStub, BindingContext bindingContext) {
return new GeneratedLightClassData(javaFileStub, "", null);
}
@Override
public void generate(@NotNull GenerationState state, @NotNull Collection<JetFile> files) {
NamespaceCodegen codegen = state.getFactory().forNamespace(packageFqName, files);
codegen.generate(CompilationErrorHandler.THROW_EXCEPTION);
state.getFactory().asList();
}
});
@NotNull
@Override
public FqName getPackageFqName() {
return packageFqName;
}
@Override
public void generate(@NotNull GenerationState state, @NotNull Collection<JetFile> files) {
NamespaceCodegen codegen = state.getFactory().forNamespace(packageFqName, files);
codegen.generate(CompilationErrorHandler.THROW_EXCEPTION);
state.getFactory().asList();
}
}
);
}
@NotNull
public static KotlinJavaFileStubProvider createForDeclaredTopLevelClass(@NotNull final JetClassOrObject classOrObject) {
return new KotlinJavaFileStubProvider(classOrObject.getProject(), new StubGenerationStrategy.WithDeclaredClasses() {
private JetFile getFile() {
JetFile file = (JetFile) classOrObject.getContainingFile();
assert classOrObject.getParent() == file : "Not a top-level class: " + classOrObject.getText();
return file;
}
public static KotlinJavaFileStubProvider createForDeclaredClass(@NotNull final JetClassOrObject classOrObject) {
return new KotlinJavaFileStubProvider(
classOrObject.getProject(),
JetPsiUtil.isLocal(classOrObject),
new StubGenerationStrategy.WithDeclaredClasses() {
private JetFile getFile() {
return (JetFile) classOrObject.getContainingFile();
}
@NotNull
@Override
public Collection<JetFile> getFiles() {
return Collections.singletonList(getFile());
}
@NotNull
@Override
public LightClassConstructionContext createLightClassConstructionContext(@NotNull Collection<JetFile> files) {
return LightClassGenerationSupport.getInstance(classOrObject.getProject()).analyzeRelevantCode(classOrObject);
}
@NotNull
@Override
public FqName getPackageFqName() {
return JetPsiUtil.getFQName(getFile());
}
@NotNull
@Override
public GeneratedLightClassData createStubWithName(PsiJavaFileStub javaFileStub, BindingContext bindingContext) {
ClassDescriptor classDescriptor = bindingContext.get(BindingContext.CLASS, classOrObject);
assert (classDescriptor != null);
@Override
public void generate(@NotNull GenerationState state, @NotNull Collection<JetFile> files) {
NamespaceCodegen namespaceCodegen = state.getFactory().forNamespace(getPackageFqName(), files);
namespaceCodegen.generateClassOrObject(classOrObject);
state.getFactory().asList();
}
});
Type asmType = bindingContext.get(CodegenBinding.ASM_TYPE, classDescriptor);
assert (asmType != null);
String jvmInternalName = asmType.getClassName();
assert (jvmInternalName != null);
return new GeneratedLightClassData(javaFileStub, jvmInternalName, classDescriptor);
}
@NotNull
@Override
public Collection<JetFile> getFiles() {
return Collections.singletonList(getFile());
}
@NotNull
@Override
public FqName getPackageFqName() {
return JetPsiUtil.getFQName(getFile());
}
@Override
public void generate(@NotNull GenerationState state, @NotNull Collection<JetFile> files) {
NamespaceCodegen namespaceCodegen = state.getFactory().forNamespace(getPackageFqName(), files);
namespaceCodegen.generateClassOrObject(classOrObject);
state.getFactory().asList();
}
}
);
}
private static final Logger LOG = Logger.getInstance(KotlinJavaFileStubProvider.class);
private final Project project;
private final StubGenerationStrategy stubGenerationStrategy;
private final boolean local;
private KotlinJavaFileStubProvider(
@NotNull Project project,
boolean local,
@NotNull StubGenerationStrategy stubGenerationStrategy
) {
this.project = project;
this.stubGenerationStrategy = stubGenerationStrategy;
this.local = local;
}
@Nullable
@Override
public Result<PsiJavaFileStub> compute() {
public Result<GeneratedLightClassData> compute() {
FqName packageFqName = stubGenerationStrategy.getPackageFqName();
Collection<JetFile> files = stubGenerationStrategy.getFiles();
checkForBuiltIns(packageFqName, files);
LightClassConstructionContext context = LightClassGenerationSupport.getInstance(project).analyzeRelevantCode(files);
LightClassConstructionContext context = stubGenerationStrategy.createLightClassConstructionContext(files);
Throwable error = context.getError();
if (error != null) {
throw new IllegalStateException("failed to analyze: " + error, error);
}
PsiJavaFileStub javaFileStub = createJavaFileStub(packageFqName, getRepresentativeVirtualFile(files));
BindingContext bindingContext;
try {
Stack<StubElement> stubStack = new Stack<StubElement>();
stubStack.push(javaFileStub);
@@ -157,6 +202,8 @@ public class KotlinJavaFileStubProvider implements CachedValueProvider<PsiJavaFi
InlineUtil.DEFAULT_INLINE_FLAG_FOR_STUB);
state.beforeCompile();
bindingContext = state.getBindingContext();
stubGenerationStrategy.generate(state, files);
StubElement pop = stubStack.pop();
@@ -173,7 +220,10 @@ public class KotlinJavaFileStubProvider implements CachedValueProvider<PsiJavaFi
throw e;
}
return Result.create(javaFileStub, PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT);
return Result.create(
stubGenerationStrategy.createStubWithName(javaFileStub, bindingContext),
local ? PsiModificationTracker.MODIFICATION_COUNT : PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT
);
}
@NotNull
@@ -231,6 +281,9 @@ public class KotlinJavaFileStubProvider implements CachedValueProvider<PsiJavaFi
}
private interface StubGenerationStrategy {
@NotNull LightClassConstructionContext createLightClassConstructionContext(@NotNull Collection<JetFile> files);
@NotNull
GeneratedLightClassData createStubWithName(PsiJavaFileStub javaFileStub, BindingContext bindingContext);
@NotNull Collection<JetFile> getFiles();
@NotNull FqName getPackageFqName();
boolean generateDeclaredClasses();
@@ -42,7 +42,7 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.codegen.binding.PsiCodegenPredictor;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.*;
import org.jetbrains.jet.lang.resolve.java.JvmClassName;
import org.jetbrains.jet.lang.resolve.java.jetAsJava.JetJavaMirrorMarker;
import org.jetbrains.jet.lang.resolve.name.FqName;
@@ -59,7 +59,7 @@ import java.util.List;
import static org.jetbrains.jet.lexer.JetTokens.*;
public class KotlinLightClassForExplicitDeclaration extends KotlinWrappingLightClass implements KotlinLightClass, JetJavaMirrorMarker {
private final static Key<CachedValue<PsiJavaFileStub>> JAVA_API_STUB = Key.create("JAVA_API_STUB");
private final static Key<CachedValue<GeneratedLightClassData>> JAVA_API_STUB = Key.create("JAVA_API_STUB");
@Nullable
public static KotlinLightClassForExplicitDeclaration create(@NotNull PsiManager manager, @NotNull JetClassOrObject classOrObject) {
@@ -67,18 +67,21 @@ public class KotlinLightClassForExplicitDeclaration extends KotlinWrappingLightC
return null;
}
// TODO temporary not building light classes for local classes: e.g., they won't be visible in hierarchy
if (JetPsiUtil.getOutermostClassOrObject(classOrObject) == null) {
return null;
}
String jvmInternalName = PsiCodegenPredictor.getPredefinedJvmInternalName(classOrObject);
String jvmInternalName = getJvmInternalName(classOrObject);
if (jvmInternalName == null) return null;
FqName fqName = JvmClassName.byInternalName(jvmInternalName).getFqNameForClassNameWithoutDollars();
return new KotlinLightClassForExplicitDeclaration(manager, fqName, classOrObject);
}
private static String getJvmInternalName(JetClassOrObject classOrObject) {
if (JetPsiUtil.isLocal(classOrObject)) {
return getGeneratedLightClassData(classOrObject).getJvmInternalName();
}
return PsiCodegenPredictor.getPredefinedJvmInternalName(classOrObject);
}
private final FqName classFqName; // FqName of (possibly inner) class
private final JetClassOrObject classOrObject;
private PsiClass delegate;
@@ -153,12 +156,31 @@ public class KotlinLightClassForExplicitDeclaration extends KotlinWrappingLightC
@NotNull
private PsiJavaFileStub getJavaFileStub() {
return getGeneratedLightClassData().getJavaFileStub();
}
@NotNull
private ClassDescriptor getDescriptor() {
ClassDescriptor descriptor = getGeneratedLightClassData().getDescriptor();
assert descriptor != null;
return descriptor;
}
@NotNull
private GeneratedLightClassData getGeneratedLightClassData() {
return getGeneratedLightClassData(classOrObject);
}
@NotNull
private static GeneratedLightClassData getGeneratedLightClassData(JetClassOrObject classOrObject) {
JetClassOrObject outermostClassOrObject = getOutermostClassOrObject(classOrObject);
return CachedValuesManager.getManager(getProject()).getCachedValue(
return CachedValuesManager.getManager(classOrObject.getProject()).getCachedValue(
outermostClassOrObject,
JAVA_API_STUB,
KotlinJavaFileStubProvider.createForDeclaredTopLevelClass(outermostClassOrObject),
/*trackValue = */false);
KotlinJavaFileStubProvider.createForDeclaredClass(outermostClassOrObject),
/*trackValue = */false
);
}
@NotNull
@@ -392,6 +414,19 @@ public class KotlinLightClassForExplicitDeclaration extends KotlinWrappingLightC
return classOrObject.isValid();
}
@Override
public boolean isInheritor(@NotNull PsiClass baseClass, boolean checkDeep) {
String qualifiedName;
if (baseClass instanceof KotlinLightClassForExplicitDeclaration) {
qualifiedName = DescriptorUtils.getFQName(((KotlinLightClassForExplicitDeclaration) baseClass).getDescriptor()).asString();
}
else {
qualifiedName = baseClass.getQualifiedName();
}
return ResolvePackage.checkSuperTypeByFQName(getDescriptor(), qualifiedName, checkDeep);
}
@Override
public PsiElement setName(@NonNls @NotNull String name) throws IncorrectOperationException {
throw new IncorrectOperationException("Cannot modify compiled kotlin element");
@@ -21,7 +21,6 @@ import com.intellij.navigation.ItemPresentation;
import com.intellij.navigation.ItemPresentationProviders;
import com.intellij.openapi.util.Comparing;
import com.intellij.psi.*;
import com.intellij.psi.impl.java.stubs.PsiJavaFileStub;
import com.intellij.psi.impl.light.LightEmptyImplementsList;
import com.intellij.psi.impl.light.LightModifierList;
import com.intellij.psi.javadoc.PsiDocComment;
@@ -32,8 +31,8 @@ import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.java.jetAsJava.JetJavaMirrorMarker;
import org.jetbrains.jet.lang.resolve.java.PackageClassUtils;
import org.jetbrains.jet.lang.resolve.java.jetAsJava.JetJavaMirrorMarker;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.plugin.JetLanguage;
@@ -48,7 +47,7 @@ public class KotlinLightClassForPackage extends KotlinWrappingLightClass impleme
private final GlobalSearchScope searchScope;
private final Collection<JetFile> files;
private final int hashCode;
private final CachedValue<PsiJavaFileStub> javaFileStub;
private final CachedValue<GeneratedLightClassData> javaFileStub;
private final PsiModifierList modifierList;
private final LightEmptyImplementsList implementsList;
@@ -266,7 +265,7 @@ public class KotlinLightClassForPackage extends KotlinWrappingLightClass impleme
@NotNull
@Override
public PsiClass getDelegate() {
PsiClass psiClass = LightClassUtil.findClass(packageClassFqName, javaFileStub.getValue());
PsiClass psiClass = LightClassUtil.findClass(packageClassFqName, javaFileStub.getValue().getJavaFileStub());
if (psiClass == null) {
throw new IllegalStateException("Package class was not found " + packageFqName);
}
@@ -38,6 +38,9 @@ public abstract class LightClassGenerationSupport {
@NotNull
public abstract LightClassConstructionContext analyzeRelevantCode(@NotNull Collection<JetFile> files);
@NotNull
public abstract LightClassConstructionContext analyzeRelevantCode(@NotNull JetClassOrObject classOrObject);
@NotNull
public abstract Collection<JetClassOrObject> findClassOrObjectDeclarations(@NotNull FqName fqName, @NotNull GlobalSearchScope searchScope);
@@ -78,10 +78,10 @@ public class JetPsiUtilTest extends JetLiteFixture {
for (JetClassOrObject classOrObject : classOrObjects) {
String classOrObjectName = classOrObject.getName();
if (classOrObjectName != null && classOrObjectName.contains("Local")) {
assertTrue("JetPsiUtil.isLocalClass should return true for " + classOrObjectName, JetPsiUtil.isLocalClass(classOrObject));
assertTrue("JetPsiUtil.isLocalClass should return true for " + classOrObjectName, JetPsiUtil.isLocal(classOrObject));
}
else {
assertFalse("JetPsiUtil.isLocalClass should return false for " + classOrObjectName, JetPsiUtil.isLocalClass(classOrObject));
assertFalse("JetPsiUtil.isLocalClass should return false for " + classOrObjectName, JetPsiUtil.isLocal(classOrObject));
}
}
}
@@ -0,0 +1,38 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.lang.resolve
import org.jetbrains.jet.lang.descriptors.ClassDescriptor
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor
public fun ClassDescriptor.checkSuperTypeByFQName(qualifiedName: String, deep: Boolean): Boolean {
fun checkDescriptor(descriptor: DeclarationDescriptor): Boolean {
return qualifiedName == DescriptorUtils.getFQName(descriptor).asString()
}
if (deep && checkDescriptor(this)) return true
for (superType in getTypeConstructor().getSupertypes()) {
val superDescriptor = superType.getConstructor().getDeclarationDescriptor()
if (superDescriptor is ClassDescriptor) {
if (checkDescriptor(superDescriptor)) return true
if (deep && superDescriptor.checkSuperTypeByFQName(qualifiedName, deep)) return true
}
}
return false
}
@@ -67,6 +67,13 @@ public class IDELightClassGenerationSupport extends LightClassGenerationSupport
return new LightClassConstructionContext(declarationsCache.getBindingContext(), null);
}
@NotNull
@Override
public LightClassConstructionContext analyzeRelevantCode(@NotNull JetClassOrObject classOrObject) {
KotlinCacheManager cacheManager = KotlinCacheManager.getInstance(project);
return new LightClassConstructionContext(cacheManager.getLightClassContextCache().getLightClassContext(classOrObject), null);
}
@NotNull
@Override
public Collection<JetClassOrObject> findClassOrObjectDeclarations(@NotNull FqName fqName, @NotNull GlobalSearchScope searchScope) {
@@ -23,22 +23,26 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.DefaultModificationTracker;
import com.intellij.openapi.util.ModificationTracker;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.asJava.KotlinLightClassContextCache;
import org.jetbrains.jet.plugin.project.TargetPlatform;
import java.util.Map;
public class KotlinCacheManager {
@NotNull
public static KotlinCacheManager getInstance(@NotNull Project project) {
return ServiceManager.getService(project, KotlinCacheManager.class);
}
private final Map<TargetPlatform, DeclarationsCacheProvider> cacheProviders = Maps.newHashMap();
private final KotlinLightClassContextCache lightClassContextCache;
private final DefaultModificationTracker kotlinDeclarationsTracker = new DefaultModificationTracker();
public KotlinCacheManager(@NotNull Project project) {
cacheProviders.put(TargetPlatform.JVM, new JvmDeclarationsCacheProvider(project));
cacheProviders.put(TargetPlatform.JS, new JSDeclarationsCacheProvider(project));
lightClassContextCache = new KotlinLightClassContextCache(project);
}
/**
@@ -84,6 +88,10 @@ public class KotlinCacheManager {
return provider;
}
public KotlinLightClassContextCache getLightClassContextCache() {
return lightClassContextCache;
}
public void invalidateCache() {
kotlinDeclarationsTracker.incModificationCount();
}
@@ -0,0 +1,79 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.asJava
import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.CachedValueProvider.Result
import org.jetbrains.jet.lang.resolve.BindingContext
import org.jetbrains.jet.lang.psi.JetClassOrObject
import com.intellij.openapi.project.Project
import org.jetbrains.jet.lang.psi.JetPsiUtil
import com.intellij.openapi.util.Key
import java.util.HashMap
import com.intellij.psi.util.PsiModificationTracker
import org.jetbrains.jet.plugin.caches.resolve.KotlinCacheManager
import org.jetbrains.jet.lang.psi.JetDeclaration
import org.jetbrains.jet.lang.psi.JetNamedFunction
import org.jetbrains.jet.lang.psi.JetProperty
import org.jetbrains.jet.lang.psi.JetClassInitializer
import org.jetbrains.jet.plugin.project.ResolveElementCache
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacadeForJVM
import java.util.Collections
import org.jetbrains.jet.lang.psi.JetFile
import com.intellij.psi.util.CachedValuesManager
import com.intellij.psi.util.CachedValue
import org.jetbrains.jet.lang.resolve.DelegatingBindingTrace
import org.jetbrains.jet.di.InjectorForJavaDescriptorResolver
import org.jetbrains.jet.lang.resolve.java.JetFilesProvider
import com.intellij.psi.search.GlobalSearchScope
class KotlinLightClassContextCache(val project: Project) {
private val cacheKey = Key.create<CachedValue<ResolveElementCache>>("KOTLIN_LIGHT_CLASS_CONTEXT_CACHE")
private val lock = Any()
private val provider = object: CachedValueProvider<ResolveElementCache> {
override fun compute(): CachedValueProvider.Result<ResolveElementCache> {
val trace = DelegatingBindingTrace(
KotlinCacheManager.getInstance(project).getPossiblyIncompleteDeclarationsForLightClassGeneration().getBindingContext(),
"Trace for KotlinLightClassContextCache"
)
val resolveSession = AnalyzerFacadeForJVM.createLazyResolveSession(
project,
JetFilesProvider.getInstance(project)!!.allInScope(GlobalSearchScope.allScope(project)),
trace,
InjectorForJavaDescriptorResolver(project, trace),
true
)
return Result.create(
ResolveElementCache(resolveSession, project),
PsiModificationTracker.MODIFICATION_COUNT,
KotlinCacheManager.getInstance(project).getDeclarationsTracker()
)
}
}
public fun getLightClassContext(classOrObject: JetClassOrObject): BindingContext {
if (!JetPsiUtil.isLocal(classOrObject)) {
return KotlinCacheManager.getInstance(project).getPossiblyIncompleteDeclarationsForLightClassGeneration().getBindingContext()
}
val resolveElementCache = CachedValuesManager.getManager(project).getCachedValue(project, cacheKey, provider, false)
return resolveElementCache?.resolveElement(classOrObject) ?: BindingContext.EMPTY
}
}
@@ -360,7 +360,7 @@ public class JetSourceNavigationHelper {
}
}
}
return JetPsiUtil.isLocalClass(classOrObject) ? null : LightClassUtil.getPsiClass(classOrObject);
return LightClassUtil.getPsiClass(classOrObject);
}
@Nullable
@@ -117,6 +117,7 @@ public class PluginJetFilesProvider extends JetFilesProvider {
!JetPluginUtil.isKtFileInGradleProjectInWrongFolder(virtualFile, project);
}
@NotNull
@Override
public Collection<JetFile> allInScope(@NotNull GlobalSearchScope scope) {
return cache.getValue(scope);
@@ -26,12 +26,10 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor;
import org.jetbrains.jet.lang.psi.JetClassOrObject;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.lazy.KotlinCodeAnalyzer;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.plugin.libraries.JetSourceNavigationHelper;
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache;
import org.jetbrains.jet.plugin.search.usagesSearch.UsagesSearchPackage;
import org.jetbrains.jet.plugin.stubindex.JetSuperClassIndex;
import java.util.Collection;
@@ -60,9 +58,9 @@ public class KotlinDirectInheritorsSearcher extends QueryExecutorBase<PsiClass,
GlobalSearchScope scope = (GlobalSearchScope) queryParameters.getScope();
Collection<JetClassOrObject> candidates = JetSuperClassIndex.getInstance().get(name, clazz.getProject(), scope);
for (JetClassOrObject candidate : candidates) {
JetFile containingFile = (JetFile) candidate.getContainingFile();
KotlinCodeAnalyzer sessionForFile = AnalyzerFacadeWithCache.getLazyResolveSessionForFile(containingFile);
ClassDescriptor classDescriptor = (ClassDescriptor) sessionForFile.resolveToDescriptor(candidate);
ClassDescriptor classDescriptor = (ClassDescriptor) UsagesSearchPackage.getDescriptor(candidate);
if (classDescriptor == null) continue;
for (JetType type : classDescriptor.getTypeConstructor().getSupertypes()) {
ClassifierDescriptor declarationDescriptor = type.getConstructor().getDeclarationDescriptor();
if (declarationDescriptor != null) {