KotlinLightClassForExplicitDeclaration: J2K

This commit is contained in:
Dmitry Jemerov
2015-08-18 20:06:38 +02:00
parent 4b2a662eb3
commit f2ff752dd1
4 changed files with 309 additions and 420 deletions
@@ -189,7 +189,7 @@ public class CliLightClassGenerationSupport extends LightClassGenerationSupport
@Nullable @Nullable
@Override @Override
public PsiClass getPsiClass(@NotNull JetClassOrObject classOrObject) { public PsiClass getPsiClass(@NotNull JetClassOrObject classOrObject) {
return KotlinLightClassForExplicitDeclaration.create(psiManager, classOrObject); return KotlinLightClassForExplicitDeclaration.Companion.create(psiManager, classOrObject);
} }
@NotNull @NotNull
@@ -44,7 +44,7 @@ class KotlinLightClassForAnonymousDeclaration extends KotlinLightClassForExplici
@NotNull @NotNull
@Override @Override
public PsiJavaCodeReferenceElement getBaseClassReference() { public PsiJavaCodeReferenceElement getBaseClassReference() {
return JavaPsiFacade.getElementFactory(classOrObject.getProject()).createReferenceElementByType(getBaseClassType()); return JavaPsiFacade.getElementFactory(getClassOrObject().getProject()).createReferenceElementByType(getBaseClassType());
} }
@NotNull @NotNull
@@ -85,7 +85,7 @@ class KotlinLightClassForAnonymousDeclaration extends KotlinLightClassForExplici
} }
if (type == null) { if (type == null) {
Project project = classOrObject.getProject(); Project project = getClassOrObject().getProject();
type = PsiType.getJavaLangObject(PsiManager.getInstance(project), GlobalSearchScope.allScope(project)); type = PsiType.getJavaLangObject(PsiManager.getInstance(project), GlobalSearchScope.allScope(project));
} }
@@ -14,593 +14,482 @@
* limitations under the License. * limitations under the License.
*/ */
package org.jetbrains.kotlin.asJava; package org.jetbrains.kotlin.asJava
import com.google.common.collect.Lists; import com.google.common.collect.Lists
import com.google.common.collect.Sets; import com.google.common.collect.Sets
import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Comparing
import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Key
import com.intellij.openapi.util.NullableLazyValue; import com.intellij.openapi.util.NullableLazyValue
import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Pair
import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*
import com.intellij.psi.*; import com.intellij.psi.impl.compiled.ClsFileImpl
import com.intellij.psi.PsiPackage; import com.intellij.psi.impl.java.stubs.PsiJavaFileStub
import com.intellij.psi.impl.compiled.ClsFileImpl; import com.intellij.psi.impl.light.LightClass
import com.intellij.psi.impl.java.stubs.PsiJavaFileStub; import com.intellij.psi.impl.light.LightMethod
import com.intellij.psi.impl.light.LightClass; import com.intellij.psi.scope.PsiScopeProcessor
import com.intellij.psi.impl.light.LightMethod; import com.intellij.psi.search.SearchScope
import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.stubs.PsiClassHolderFileStub
import com.intellij.psi.search.SearchScope; import com.intellij.psi.util.CachedValue
import com.intellij.psi.stubs.PsiClassHolderFileStub; import com.intellij.psi.util.CachedValuesManager
import com.intellij.psi.util.CachedValue; import com.intellij.psi.util.PsiTreeUtil
import com.intellij.psi.util.CachedValuesManager; import com.intellij.util.ArrayUtil
import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.IncorrectOperationException
import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NonNls
import com.intellij.util.IncorrectOperationException; import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import kotlin.KotlinPackage; import org.jetbrains.kotlin.codegen.binding.PsiCodegenPredictor
import kotlin.jvm.functions.Function1; import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.annotations.NonNls; import org.jetbrains.kotlin.idea.JetLanguage
import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.lexer.JetTokens.*
import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.codegen.binding.PsiCodegenPredictor; import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.descriptors.ClassDescriptor; import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor; import javax.swing.Icon
import org.jetbrains.kotlin.idea.JetLanguage;
import org.jetbrains.kotlin.lexer.JetModifierKeywordToken;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.jvm.JvmClassName;
import org.jetbrains.kotlin.types.JetType;
import javax.swing.*; public open class KotlinLightClassForExplicitDeclaration(
import java.util.Collection; manager: PsiManager,
import java.util.List; private val classFqName: FqName // FqName of (possibly inner) class
,
protected val classOrObject: JetClassOrObject) : KotlinWrappingLightClass(manager), JetJavaMirrorMarker {
private var delegate: PsiClass? = null
import static org.jetbrains.kotlin.lexer.JetTokens.*; private val parent = object : NullableLazyValue<PsiElement>() {
override fun compute(): PsiElement? {
public class KotlinLightClassForExplicitDeclaration extends KotlinWrappingLightClass implements JetJavaMirrorMarker {
private final static Key<CachedValue<OutermostKotlinClassLightClassData>> JAVA_API_STUB = Key.create("JAVA_API_STUB");
@Nullable
public static KotlinLightClassForExplicitDeclaration create(@NotNull PsiManager manager, @NotNull JetClassOrObject classOrObject) {
if (LightClassUtil.belongsToKotlinBuiltIns(classOrObject.getContainingJetFile())) {
return null;
}
FqName fqName = predictFqName(classOrObject);
if (fqName == null) return null;
if (classOrObject instanceof JetObjectDeclaration && ((JetObjectDeclaration) classOrObject).isObjectLiteral()) {
return new KotlinLightClassForAnonymousDeclaration(manager, fqName, classOrObject);
}
return new KotlinLightClassForExplicitDeclaration(manager, fqName, classOrObject);
}
@Nullable
private static FqName predictFqName(@NotNull JetClassOrObject classOrObject) {
if (classOrObject.isLocal()) {
LightClassDataForKotlinClass data = getLightClassDataExactly(classOrObject);
return data == null ? null : data.getJvmQualifiedName();
}
String internalName = PsiCodegenPredictor.getPredefinedJvmInternalName(classOrObject);
return internalName == null ? null : JvmClassName.byInternalName(internalName).getFqNameForClassNameWithoutDollars();
}
private final FqName classFqName; // FqName of (possibly inner) class
protected final JetClassOrObject classOrObject;
private PsiClass delegate;
private final NullableLazyValue<PsiElement> parent = new NullableLazyValue<PsiElement>() {
@Nullable
@Override
protected PsiElement compute() {
if (classOrObject.isLocal()) { if (classOrObject.isLocal()) {
//noinspection unchecked //noinspection unchecked
PsiElement declaration = JetPsiUtil.getTopmostParentOfTypes( var declaration: PsiElement? = JetPsiUtil.getTopmostParentOfTypes(
classOrObject, classOrObject,
JetNamedFunction.class, JetConstructor.class, JetProperty.class, JetClassInitializer.class, JetParameter.class javaClass<JetNamedFunction>(), javaClass<JetConstructor<*>>(), javaClass<JetProperty>(), javaClass<JetClassInitializer>(), javaClass<JetParameter>())
);
if (declaration instanceof JetParameter) { if (declaration is JetParameter) {
declaration = PsiTreeUtil.getParentOfType(declaration, JetNamedDeclaration.class); declaration = PsiTreeUtil.getParentOfType(declaration, javaClass<JetNamedDeclaration>())
} }
if (declaration instanceof JetFunction) { if (declaration is JetFunction) {
JetFunction function = (JetFunction) declaration; return getParentByPsiMethod(LightClassUtil.getLightClassMethod(declaration), declaration.name, false)
return getParentByPsiMethod(LightClassUtil.getLightClassMethod(function), function.getName(), false);
} }
// Represent the property as a fake method with the same name // Represent the property as a fake method with the same name
if (declaration instanceof JetProperty) { if (declaration is JetProperty) {
JetProperty property = (JetProperty) declaration; return getParentByPsiMethod(LightClassUtil.getLightClassPropertyMethods(declaration).getter, declaration.name, true)
return getParentByPsiMethod(LightClassUtil.getLightClassPropertyMethods(property).getGetter(), property.getName(), true);
} }
if (declaration instanceof JetClassInitializer) { if (declaration is JetClassInitializer) {
PsiElement parent = declaration.getParent(); val parent = declaration.parent
PsiElement grandparent = parent.getParent(); val grandparent = parent.parent
if (parent instanceof JetClassBody && grandparent instanceof JetClassOrObject) { if (parent is JetClassBody && grandparent is JetClassOrObject) {
return LightClassUtil.getPsiClass((JetClassOrObject) grandparent); return LightClassUtil.getPsiClass(grandparent)
} }
} }
if (declaration instanceof JetClass) { if (declaration is JetClass) {
return LightClassUtil.getPsiClass((JetClass) declaration); return LightClassUtil.getPsiClass(declaration)
} }
} }
return classOrObject.getParent() == classOrObject.getContainingFile() ? getContainingFile() : getContainingClass(); return if (classOrObject.parent === classOrObject.containingFile) containingFile else containingClass
} }
private PsiElement getParentByPsiMethod(PsiMethod method, final String name, boolean forceMethodWrapping) { private fun getParentByPsiMethod(method: PsiMethod?, name: String?, forceMethodWrapping: Boolean): PsiElement? {
if (method == null || name == null) return null; if (method == null || name == null) return null
PsiClass containingClass = method.getContainingClass(); var containingClass: com.intellij.psi.PsiClass? = method.containingClass ?: return null
if (containingClass == null) return null;
final String currentFileName = classOrObject.getContainingFile().getName(); val currentFileName = classOrObject.containingFile.name
boolean createWrapper = forceMethodWrapping; var createWrapper = forceMethodWrapping
// Use PsiClass wrapper instead of package light class to avoid names like "FooPackage" in Type Hierarchy and related views // Use PsiClass wrapper instead of package light class to avoid names like "FooPackage" in Type Hierarchy and related views
if (containingClass instanceof KotlinLightClassForPackage) { if (containingClass is KotlinLightClassForPackage) {
containingClass = new LightClass(containingClass, JetLanguage.INSTANCE) { containingClass = object : LightClass(containingClass as KotlinLightClassForPackage, JetLanguage.INSTANCE) {
@Nullable override fun getName(): String? {
@Override return currentFileName
public String getName() {
return currentFileName;
} }
}; }
createWrapper = true; createWrapper = true
} }
if (createWrapper) { if (createWrapper) {
return new LightMethod(myManager, method, containingClass, JetLanguage.INSTANCE) { return object : LightMethod(myManager, method, containingClass!!, JetLanguage.INSTANCE) {
@Override override fun getParent(): PsiElement {
public PsiElement getParent() { return getContainingClass()!!
return getContainingClass();
} }
@NotNull override fun getName(): String {
@Override return name
public String getName() {
return name;
} }
}; }
} }
return method; return method
} }
}; }
@Nullable private var modifierList: PsiModifierList? = null
private PsiModifierList modifierList;
private final NullableLazyValue<PsiTypeParameterList> typeParameterList = new NullableLazyValue<PsiTypeParameterList>() { private val typeParameterList = object : NullableLazyValue<PsiTypeParameterList>() {
@Nullable override fun compute(): PsiTypeParameterList? {
@Override return LightClassUtil.buildLightTypeParameterList(this@KotlinLightClassForExplicitDeclaration, classOrObject)
protected PsiTypeParameterList compute() {
return LightClassUtil.buildLightTypeParameterList(KotlinLightClassForExplicitDeclaration.this, classOrObject);
} }
};
KotlinLightClassForExplicitDeclaration(
@NotNull PsiManager manager,
@NotNull FqName name,
@NotNull JetClassOrObject classOrObject
) {
super(manager);
this.classFqName = name;
this.classOrObject = classOrObject;
} }
@Override override fun getOrigin(): JetClassOrObject {
@NotNull return classOrObject
public JetClassOrObject getOrigin() {
return classOrObject;
} }
@NotNull override fun getFqName(): FqName {
@Override return classFqName
public FqName getFqName() {
return classFqName;
} }
@NotNull override fun copy(): PsiElement {
@Override return KotlinLightClassForExplicitDeclaration(manager, classFqName, classOrObject.copy() as JetClassOrObject)
public PsiElement copy() {
return new KotlinLightClassForExplicitDeclaration(getManager(), classFqName, (JetClassOrObject) classOrObject.copy());
} }
@NotNull override fun getDelegate(): PsiClass {
@Override
public PsiClass getDelegate() {
if (delegate == null) { if (delegate == null) {
PsiJavaFileStub javaFileStub = getJavaFileStub(); val javaFileStub = getJavaFileStub()
PsiClass psiClass = LightClassUtil.findClass(classFqName, javaFileStub); val psiClass = LightClassUtil.findClass(classFqName, javaFileStub)
if (psiClass == null) { if (psiClass == null) {
JetClassOrObject outermostClassOrObject = getOutermostClassOrObject(classOrObject); val outermostClassOrObject = getOutermostClassOrObject(classOrObject)
throw new IllegalStateException("Class was not found " + classFqName + "\n" + throw IllegalStateException("Class was not found " + classFqName + "\n" + "in " + outermostClassOrObject.containingFile.text + "\n" + "stub: \n" + javaFileStub.psi.text)
"in " + outermostClassOrObject.getContainingFile().getText() + "\n" +
"stub: \n" + javaFileStub.getPsi().getText());
} }
delegate = psiClass; delegate = psiClass
} }
return delegate; return delegate!!
} }
@NotNull private fun getJavaFileStub(): PsiJavaFileStub {
private PsiJavaFileStub getJavaFileStub() { return getLightClassData().javaFileStub
return getLightClassData().getJavaFileStub();
} }
@Nullable protected fun getDescriptor(): ClassDescriptor? {
protected final ClassDescriptor getDescriptor() { val data = getLightClassDataExactly(classOrObject)
LightClassDataForKotlinClass data = getLightClassDataExactly(classOrObject); return data?.descriptor
return data != null ? data.getDescriptor() : null;
} }
@NotNull private fun getLightClassData(): OutermostKotlinClassLightClassData {
private OutermostKotlinClassLightClassData getLightClassData() { return getLightClassData(classOrObject)
return getLightClassData(classOrObject);
} }
@NotNull private val _containingFile = object : NullableLazyValue<PsiFile>() {
public static OutermostKotlinClassLightClassData getLightClassData(@NotNull JetClassOrObject classOrObject) { override fun compute(): PsiFile? {
JetClassOrObject outermostClassOrObject = getOutermostClassOrObject(classOrObject); val virtualFile = classOrObject.containingFile.virtualFile
return CachedValuesManager.getManager(classOrObject.getProject()).getCachedValue( assert(virtualFile != null) { "No virtual file for " + classOrObject.text }
outermostClassOrObject, return object : ClsFileImpl(ClassFileViewProvider(getManager(), virtualFile)) {
JAVA_API_STUB, override fun getPackageName(): String {
KotlinJavaFileStubProvider.createForDeclaredClass(outermostClassOrObject), return classOrObject.getContainingJetFile().packageFqName.asString()
/*trackValue = */false
);
}
@Nullable
private static LightClassDataForKotlinClass getLightClassDataExactly(JetClassOrObject classOrObject) {
OutermostKotlinClassLightClassData data = getLightClassData(classOrObject);
return data.getClassOrObject().equals(classOrObject) ? data : data.getAllInnerClasses().get(classOrObject);
}
@NotNull
private static JetClassOrObject getOutermostClassOrObject(@NotNull JetClassOrObject classOrObject) {
JetClassOrObject outermostClass = JetPsiUtil.getOutermostClassOrObject(classOrObject);
if (outermostClass == null) {
throw new IllegalStateException("Attempt to build a light class for a local class: " + classOrObject.getText());
}
else {
return outermostClass;
}
}
private final NullableLazyValue<PsiFile> _containingFile = new NullableLazyValue<PsiFile>() {
@Nullable
@Override
protected PsiFile compute() {
VirtualFile virtualFile = classOrObject.getContainingFile().getVirtualFile();
assert virtualFile != null : "No virtual file for " + classOrObject.getText();
return new ClsFileImpl(new ClassFileViewProvider(getManager(), virtualFile)) {
@NotNull
@Override
public String getPackageName() {
return classOrObject.getContainingJetFile().getPackageFqName().asString();
} }
@NotNull override fun getStub(): PsiClassHolderFileStub<PsiJavaFile> {
@Override return getJavaFileStub()
public PsiClassHolderFileStub getStub() {
return getJavaFileStub();
} }
@SuppressWarnings("Contract") SuppressWarnings("Contract")
@Override override fun processDeclarations(
public boolean processDeclarations( processor: PsiScopeProcessor,
@NotNull PsiScopeProcessor processor, state: ResolveState,
@NotNull ResolveState state, lastParent: PsiElement?,
PsiElement lastParent, place: PsiElement): Boolean {
@NotNull PsiElement place if (!super.processDeclarations(processor, state, lastParent, place)) return false
) {
if (!super.processDeclarations(processor, state, lastParent, place)) return false;
// We have to explicitly process package declarations if current file belongs to default package // We have to explicitly process package declarations if current file belongs to default package
// so that Java resolve can find classes located in that package // so that Java resolve can find classes located in that package
String packageName = getPackageName(); val packageName = packageName
if (!packageName.isEmpty()) return true; if (!packageName.isEmpty()) return true
PsiPackage aPackage = JavaPsiFacade.getInstance(myManager.getProject()).findPackage(packageName); val aPackage = JavaPsiFacade.getInstance(myManager.project).findPackage(packageName)
if (aPackage != null && !aPackage.processDeclarations(processor, state, null, place)) return false; if (aPackage != null && !aPackage.processDeclarations(processor, state, null, place)) return false
return true; return true
} }
}; }
} }
};
@Override
public PsiFile getContainingFile() {
return _containingFile.getValue();
} }
@NotNull override fun getContainingFile(): PsiFile? {
@Override return _containingFile.value
public PsiElement getNavigationElement() {
return classOrObject;
} }
@Override override fun getNavigationElement(): PsiElement {
public boolean isEquivalentTo(PsiElement another) { return classOrObject
return another instanceof PsiClass && Comparing.equal(((PsiClass) another).getQualifiedName(), getQualifiedName());
} }
@Override override fun isEquivalentTo(another: PsiElement?): Boolean {
public Icon getElementIcon(int flags) { return another is PsiClass && Comparing.equal(another.getQualifiedName(), qualifiedName)
throw new UnsupportedOperationException("This should be done byt JetIconProvider");
} }
@Override override fun getElementIcon(flags: Int): Icon? {
public boolean equals(Object o) { throw UnsupportedOperationException("This should be done byt JetIconProvider")
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
KotlinLightClassForExplicitDeclaration aClass = (KotlinLightClassForExplicitDeclaration) o;
if (!classFqName.equals(aClass.classFqName)) return false;
return true;
} }
@Override override fun equals(o: Any?): Boolean {
public int hashCode() { if (this === o) return true
return classFqName.hashCode(); if (o == null || javaClass != o.javaClass) return false
val aClass = o as KotlinLightClassForExplicitDeclaration
if (classFqName != aClass.classFqName) return false
return true
} }
@Nullable override fun hashCode(): Int {
@Override return classFqName.hashCode()
public PsiClass getContainingClass() {
if (classOrObject.getParent() == classOrObject.getContainingFile()) return null;
return super.getContainingClass();
} }
@Nullable override fun getContainingClass(): PsiClass? {
@Override if (classOrObject.parent === classOrObject.containingFile) return null
public PsiElement getParent() { return super.getContainingClass()
return parent.getValue();
} }
@Override override fun getParent(): PsiElement? {
public PsiElement getContext() { return parent.value
return getParent();
} }
@Nullable override fun getContext(): PsiElement? {
@Override return getParent()
public PsiTypeParameterList getTypeParameterList() {
return typeParameterList.getValue();
} }
@NotNull override fun getTypeParameterList(): PsiTypeParameterList? {
@Override return typeParameterList.value
public PsiTypeParameter[] getTypeParameters() {
PsiTypeParameterList typeParameterList = getTypeParameterList();
return typeParameterList == null ? PsiTypeParameter.EMPTY_ARRAY : typeParameterList.getTypeParameters();
} }
@Nullable override fun getTypeParameters(): Array<PsiTypeParameter> {
@Override val typeParameterList = getTypeParameterList()
public String getName() { return if (typeParameterList == null) PsiTypeParameter.EMPTY_ARRAY else typeParameterList.typeParameters
return classFqName.shortName().asString();
} }
@Nullable override fun getName(): String? {
@Override return classFqName.shortName().asString()
public String getQualifiedName() {
return classFqName.asString();
} }
@NotNull override fun getQualifiedName(): String? {
@Override return classFqName.asString()
public PsiModifierList getModifierList() { }
override fun getModifierList(): PsiModifierList {
if (modifierList == null) { if (modifierList == null) {
modifierList = new KotlinLightModifierList(this.getManager(), computeModifiers()) { modifierList = object : KotlinLightModifierList(this.manager, computeModifiers()) {
@Override override fun getDelegate(): PsiModifierList {
public PsiAnnotationOwner getDelegate() { return this@KotlinLightClassForExplicitDeclaration.getDelegate().modifierList!!
return KotlinLightClassForExplicitDeclaration.this.getDelegate().getModifierList();
} }
}; }
} }
return modifierList; return modifierList!!
} }
@NotNull private fun computeModifiers(): Array<String> {
private String[] computeModifiers() { val psiModifiers = Sets.newHashSet<String>()
Collection<String> psiModifiers = Sets.newHashSet();
// PUBLIC, PROTECTED, PRIVATE, ABSTRACT, FINAL // PUBLIC, PROTECTED, PRIVATE, ABSTRACT, FINAL
//noinspection unchecked //noinspection unchecked
List<Pair<JetModifierKeywordToken, String>> jetTokenToPsiModifier = Lists.newArrayList( val jetTokenToPsiModifier = Lists.newArrayList(
Pair.create(PUBLIC_KEYWORD, PsiModifier.PUBLIC), Pair.create(PUBLIC_KEYWORD, PsiModifier.PUBLIC),
Pair.create(INTERNAL_KEYWORD, PsiModifier.PUBLIC), Pair.create(INTERNAL_KEYWORD, PsiModifier.PUBLIC),
Pair.create(PROTECTED_KEYWORD, PsiModifier.PROTECTED), Pair.create(PROTECTED_KEYWORD, PsiModifier.PROTECTED),
Pair.create(FINAL_KEYWORD, PsiModifier.FINAL)); Pair.create(FINAL_KEYWORD, PsiModifier.FINAL))
for (Pair<JetModifierKeywordToken, String> tokenAndModifier : jetTokenToPsiModifier) { for (tokenAndModifier in jetTokenToPsiModifier) {
if (classOrObject.hasModifier(tokenAndModifier.first)) { if (classOrObject.hasModifier(tokenAndModifier.first)) {
psiModifiers.add(tokenAndModifier.second); psiModifiers.add(tokenAndModifier.second)
} }
} }
if (classOrObject.hasModifier(PRIVATE_KEYWORD)) { if (classOrObject.hasModifier(PRIVATE_KEYWORD)) {
// Top-level private class has PUBLIC visibility in Java // Top-level private class has PUBLIC visibility in Java
// Nested private class has PRIVATE visibility // Nested private class has PRIVATE visibility
psiModifiers.add(classOrObject.isTopLevel() ? PsiModifier.PUBLIC : PsiModifier.PRIVATE); psiModifiers.add(if (classOrObject.isTopLevel()) PsiModifier.PUBLIC else PsiModifier.PRIVATE)
} }
if (!psiModifiers.contains(PsiModifier.PRIVATE) && !psiModifiers.contains(PsiModifier.PROTECTED)) { if (!psiModifiers.contains(PsiModifier.PRIVATE) && !psiModifiers.contains(PsiModifier.PROTECTED)) {
psiModifiers.add(PsiModifier.PUBLIC); // For internal (default) visibility psiModifiers.add(PsiModifier.PUBLIC) // For internal (default) visibility
} }
// FINAL // FINAL
if (isAbstract(classOrObject)) { if (isAbstract(classOrObject)) {
psiModifiers.add(PsiModifier.ABSTRACT); psiModifiers.add(PsiModifier.ABSTRACT)
} }
else if (!(classOrObject.hasModifier(OPEN_KEYWORD) || (classOrObject instanceof JetClass && ((JetClass) classOrObject).isEnum()))) { else if (!(classOrObject.hasModifier(OPEN_KEYWORD) || (classOrObject is JetClass && classOrObject.isEnum()))) {
psiModifiers.add(PsiModifier.FINAL); psiModifiers.add(PsiModifier.FINAL)
} }
if (!classOrObject.isTopLevel() && !classOrObject.hasModifier(INNER_KEYWORD)) { if (!classOrObject.isTopLevel() && !classOrObject.hasModifier(INNER_KEYWORD)) {
psiModifiers.add(PsiModifier.STATIC); psiModifiers.add(PsiModifier.STATIC)
} }
return ArrayUtil.toStringArray(psiModifiers); return ArrayUtil.toStringArray(psiModifiers)
} }
private boolean isAbstract(@NotNull JetClassOrObject object) { private fun isAbstract(`object`: JetClassOrObject): Boolean {
return object.hasModifier(ABSTRACT_KEYWORD) || isInterface(); return `object`.hasModifier(ABSTRACT_KEYWORD) || isInterface
} }
@Override override fun hasModifierProperty(NonNls name: String): Boolean {
public boolean hasModifierProperty(@NonNls @NotNull String name) { return getModifierList().hasModifierProperty(name)
return getModifierList().hasModifierProperty(name);
} }
@Override override fun isDeprecated(): Boolean {
public boolean isDeprecated() { val jetModifierList = classOrObject.modifierList ?: return false
JetModifierList jetModifierList = classOrObject.getModifierList();
if (jetModifierList == null) { val deprecatedFqName = KotlinBuiltIns.FQ_NAMES.deprecated
return false; val deprecatedName = deprecatedFqName.shortName().asString()
for (annotationEntry in jetModifierList.annotationEntries) {
val typeReference = annotationEntry.typeReference ?: continue
val typeElement = typeReference.typeElement
if (typeElement !is JetUserType) continue // If it's not a user type, it's definitely not a ref to deprecated
val fqName = JetPsiUtil.toQualifiedName(typeElement) ?: continue
if (deprecatedFqName == fqName) return true
if (deprecatedName == fqName.asString()) return true
} }
return false
FqName deprecatedFqName = KotlinBuiltIns.FQ_NAMES.deprecated;
String deprecatedName = deprecatedFqName.shortName().asString();
for (JetAnnotationEntry annotationEntry : jetModifierList.getAnnotationEntries()) {
JetTypeReference typeReference = annotationEntry.getTypeReference();
if (typeReference == null) continue;
JetTypeElement typeElement = typeReference.getTypeElement();
if (!(typeElement instanceof JetUserType)) continue; // If it's not a user type, it's definitely not a ref to deprecated
FqName fqName = JetPsiUtil.toQualifiedName((JetUserType) typeElement);
if (fqName == null) continue;
if (deprecatedFqName.equals(fqName)) return true;
if (deprecatedName.equals(fqName.asString())) return true;
}
return false;
} }
@Override override fun isInterface(): Boolean {
public boolean isInterface() { if (classOrObject !is JetClass) return false
if (!(classOrObject instanceof JetClass)) return false; return classOrObject.isInterface() || classOrObject.isAnnotation()
JetClass jetClass = (JetClass) classOrObject;
return jetClass.isInterface() || jetClass.isAnnotation();
} }
@Override override fun isAnnotationType(): Boolean {
public boolean isAnnotationType() { return classOrObject is JetClass && classOrObject.isAnnotation()
return classOrObject instanceof JetClass && ((JetClass) classOrObject).isAnnotation();
} }
@Override override fun isEnum(): Boolean {
public boolean isEnum() { return classOrObject is JetClass && classOrObject.isEnum()
return classOrObject instanceof JetClass && ((JetClass) classOrObject).isEnum();
} }
@Override override fun hasTypeParameters(): Boolean {
public boolean hasTypeParameters() { return classOrObject is JetClass && !classOrObject.typeParameters.isEmpty()
return classOrObject instanceof JetClass && !((JetClass) classOrObject).getTypeParameters().isEmpty();
} }
@Override override fun isValid(): Boolean {
public boolean isValid() { return classOrObject.isValid
return classOrObject.isValid();
} }
@Override override fun isInheritor(baseClass: PsiClass, checkDeep: Boolean): Boolean {
public boolean isInheritor(@NotNull PsiClass baseClass, boolean checkDeep) {
// Java inheritor check doesn't work when trait (interface in Java) subclasses Java class and for Kotlin local classes // Java inheritor check doesn't work when trait (interface in Java) subclasses Java class and for Kotlin local classes
if (baseClass instanceof KotlinLightClassForExplicitDeclaration || (isInterface() && !baseClass.isInterface())) { if (baseClass is KotlinLightClassForExplicitDeclaration || (isInterface && !baseClass.isInterface)) {
String qualifiedName; val qualifiedName: String?
if (baseClass instanceof KotlinLightClassForExplicitDeclaration) { if (baseClass is KotlinLightClassForExplicitDeclaration) {
ClassDescriptor baseDescriptor = ((KotlinLightClassForExplicitDeclaration) baseClass).getDescriptor(); val baseDescriptor = baseClass.getDescriptor()
qualifiedName = baseDescriptor != null ? DescriptorUtils.getFqName(baseDescriptor).asString() : null; qualifiedName = if (baseDescriptor != null) DescriptorUtils.getFqName(baseDescriptor).asString() else null
} }
else { else {
qualifiedName = baseClass.getQualifiedName(); qualifiedName = baseClass.qualifiedName
} }
ClassDescriptor thisDescriptor = getDescriptor(); val thisDescriptor = getDescriptor()
return qualifiedName != null return qualifiedName != null && thisDescriptor != null && checkSuperTypeByFQName(thisDescriptor, qualifiedName, checkDeep)
&& thisDescriptor != null
&& checkSuperTypeByFQName(thisDescriptor, qualifiedName, checkDeep);
} }
return super.isInheritor(baseClass, checkDeep); return super.isInheritor(baseClass, checkDeep)
} }
@Override throws(IncorrectOperationException::class)
public PsiElement setName(@NonNls @NotNull String name) throws IncorrectOperationException { override fun setName(NonNls name: String): PsiElement {
getOrigin().setName(name); getOrigin().setName(name)
return this; return this
} }
@Override override fun toString(): String {
public String toString() {
try { try {
return KotlinLightClass.class.getSimpleName() + ":" + getQualifiedName(); return javaClass<KotlinLightClass>().simpleName + ":" + qualifiedName
} }
catch (Throwable e) { catch (e: Throwable) {
return KotlinLightClass.class.getSimpleName() + ":" + e.toString(); return javaClass<KotlinLightClass>().simpleName + ":" + e.toString()
} }
} }
@NotNull override fun getOwnInnerClasses(): List<PsiClass> {
@Override return getDelegate().innerClasses
public List<PsiClass> getOwnInnerClasses() { .map {
return KotlinPackage.filterNotNull( val declaration = ClsWrapperStubPsiFactory.getOriginalDeclaration(it) as JetClassOrObject?
KotlinPackage.map( if (declaration != null) create(myManager, declaration) else null
getDelegate().getInnerClasses(), }
new Function1<PsiClass, PsiClass>() { .filterNotNull()
@Override }
public PsiClass invoke(PsiClass aClass) {
JetClassOrObject declaration = (JetClassOrObject) ClsWrapperStubPsiFactory.getOriginalDeclaration(aClass); override fun getUseScope(): SearchScope {
return declaration != null ? create(myManager, declaration) : null; return getOrigin().useScope
} }
companion object {
private val JAVA_API_STUB = Key.create<CachedValue<OutermostKotlinClassLightClassData>>("JAVA_API_STUB")
public fun create(manager: PsiManager, classOrObject: JetClassOrObject): KotlinLightClassForExplicitDeclaration? {
if (LightClassUtil.belongsToKotlinBuiltIns(classOrObject.getContainingJetFile())) {
return null
}
val fqName = predictFqName(classOrObject) ?: return null
if (classOrObject is JetObjectDeclaration && classOrObject.isObjectLiteral()) {
return KotlinLightClassForAnonymousDeclaration(manager, fqName, classOrObject)
}
return KotlinLightClassForExplicitDeclaration(manager, fqName, classOrObject)
}
private fun predictFqName(classOrObject: JetClassOrObject): FqName? {
if (classOrObject.isLocal()) {
val data = getLightClassDataExactly(classOrObject)
return data?.jvmQualifiedName
}
val internalName = PsiCodegenPredictor.getPredefinedJvmInternalName(classOrObject)
return if (internalName == null) null else JvmClassName.byInternalName(internalName).fqNameForClassNameWithoutDollars
}
public fun getLightClassData(classOrObject: JetClassOrObject): OutermostKotlinClassLightClassData {
val outermostClassOrObject = getOutermostClassOrObject(classOrObject)
return CachedValuesManager.getManager(classOrObject.project).getCachedValue(
outermostClassOrObject,
JAVA_API_STUB,
KotlinJavaFileStubProvider.createForDeclaredClass(outermostClassOrObject),
/*trackValue = */false)
}
private fun getLightClassDataExactly(classOrObject: JetClassOrObject): LightClassDataForKotlinClass? {
val data = getLightClassData(classOrObject)
return if (data.classOrObject == classOrObject) data else data.allInnerClasses.get(classOrObject)
}
private fun getOutermostClassOrObject(classOrObject: JetClassOrObject): JetClassOrObject {
val outermostClass = JetPsiUtil.getOutermostClassOrObject(classOrObject)
if (outermostClass == null) {
throw IllegalStateException("Attempt to build a light class for a local class: " + classOrObject.text)
}
else {
return outermostClass
}
}
private fun checkSuperTypeByFQName(classDescriptor: ClassDescriptor, qualifiedName: String, deep: Boolean?): Boolean {
if (CommonClassNames.JAVA_LANG_OBJECT == qualifiedName) return true
if (qualifiedName == DescriptorUtils.getFqName(classDescriptor).asString()) return true
for (superType in classDescriptor.typeConstructor.supertypes) {
val superDescriptor = superType.constructor.declarationDescriptor
if (superDescriptor is ClassDescriptor) {
if (qualifiedName == DescriptorUtils.getFqName(superDescriptor).asString()) return true
if (deep!!) {
if (checkSuperTypeByFQName(superDescriptor, qualifiedName, true)) {
return true
} }
)
);
}
@NotNull
@Override
public SearchScope getUseScope() {
return getOrigin().getUseScope();
}
private static boolean checkSuperTypeByFQName(@NotNull ClassDescriptor classDescriptor, @NotNull String qualifiedName, Boolean deep) {
if (CommonClassNames.JAVA_LANG_OBJECT.equals(qualifiedName)) return true;
if (qualifiedName.equals(DescriptorUtils.getFqName(classDescriptor).asString())) return true;
for (JetType superType : classDescriptor.getTypeConstructor().getSupertypes()) {
ClassifierDescriptor superDescriptor = superType.getConstructor().getDeclarationDescriptor();
if (superDescriptor instanceof ClassDescriptor) {
if (qualifiedName.equals(DescriptorUtils.getFqName(superDescriptor).asString())) return true;
if (deep) {
if (checkSuperTypeByFQName((ClassDescriptor)superDescriptor, qualifiedName, true)) {
return true;
} }
} }
} }
}
return false; return false
}
} }
} }
@@ -219,7 +219,7 @@ public class IDELightClassGenerationSupport extends LightClassGenerationSupport
} }
return JetSourceNavigationHelper.getOriginalClass(classOrObject); return JetSourceNavigationHelper.getOriginalClass(classOrObject);
} }
return KotlinLightClassForExplicitDeclaration.create(psiManager, classOrObject); return KotlinLightClassForExplicitDeclaration.Companion.create(psiManager, classOrObject);
} }
@Nullable @Nullable