Add support of light classes for local class/object declarations
This commit is contained in:
@@ -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?
|
||||
)
|
||||
+102
-49
@@ -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();
|
||||
|
||||
+46
-11
@@ -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");
|
||||
|
||||
+3
-4
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user