Compare commits

...

4 Commits

Author SHA1 Message Date
Alexey Sedunov
022b4babbd Light Classes: Generate light wrappers for name identifiers 2016-03-14 17:23:19 +03:00
Alexey Sedunov
55e0d4978b Light Classes: Generate light wrappers for annotation entries 2016-03-14 17:23:18 +03:00
Alexey Sedunov
4ae965ae87 Java To Kotlin: KtLightModifierList 2016-03-14 17:23:17 +03:00
Alexey Sedunov
d6b326d244 Java To Kotlin: KtLightModifierList.java (rename to .kt) 2016-03-14 17:23:16 +03:00
19 changed files with 239 additions and 84 deletions

View File

@@ -137,8 +137,8 @@ class CliLightClassGenerationSupport(project: Project) : LightClassGenerationSup
return KtLightClassForExplicitDeclaration.create(classOrObject)
}
override fun resolveClassToDescriptor(classOrObject: KtClassOrObject): ClassDescriptor? {
return bindingContext.get(BindingContext.CLASS, classOrObject)
override fun resolveToDescriptor(declaration: KtDeclaration): DeclarationDescriptor? {
return bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, declaration)
}
override fun getFacadeClasses(facadeFqName: FqName, scope: GlobalSearchScope): Collection<PsiClass> {

View File

@@ -0,0 +1,53 @@
/*
* Copyright 2010-2016 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.kotlin.asJava
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiAnnotation
import com.intellij.psi.PsiAnnotationOwner
import com.intellij.psi.PsiElement
import com.intellij.util.IncorrectOperationException
import org.jetbrains.kotlin.psi.KtAnnotationEntry
class KtLightAnnotation(
private val delegate: PsiAnnotation,
private val originalElement: KtAnnotationEntry?,
private val owner: PsiAnnotationOwner
) : PsiAnnotation by delegate, KtLightElement<KtAnnotationEntry, PsiAnnotation> {
override fun getDelegate() = delegate
override fun getOrigin() = originalElement
override fun getName() = null
override fun setName(newName: String) = throw IncorrectOperationException()
override fun getOwner() = owner
override fun getText() = originalElement?.text ?: ""
override fun getTextRange() = originalElement?.textRange ?: TextRange.EMPTY_RANGE
override fun getParent() = owner as? PsiElement
override fun toString() = "@$qualifiedName"
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other?.javaClass != javaClass) return false
return originalElement == (other as KtLightAnnotation).originalElement
}
override fun hashCode() = originalElement?.hashCode() ?: 0
}

View File

@@ -20,6 +20,6 @@ import com.intellij.psi.PsiClass;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.psi.KtClassOrObject
interface KtLightClass : PsiClass, KtLightElement<KtClassOrObject, PsiClass> {
interface KtLightClass : PsiClass, KtLightDeclaration<KtClassOrObject, PsiClass> {
fun getFqName(): FqName
}

View File

@@ -19,10 +19,12 @@ package org.jetbrains.kotlin.asJava
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.util.Comparing
import com.intellij.openapi.util.Key
import com.intellij.openapi.util.TextRange
import com.intellij.psi.*
import com.intellij.psi.impl.DebugUtil
import com.intellij.psi.impl.java.stubs.PsiJavaFileStub
import com.intellij.psi.impl.light.LightClass
import com.intellij.psi.impl.light.LightIdentifier
import com.intellij.psi.impl.light.LightMethod
import com.intellij.psi.scope.PsiScopeProcessor
import com.intellij.psi.search.SearchScope
@@ -170,7 +172,7 @@ open class KtLightClassForExplicitDeclaration(
private fun getJavaFileStub(): PsiJavaFileStub = getLightClassData().javaFileStub
protected fun getDescriptor(): ClassDescriptor? {
return LightClassGenerationSupport.getInstance(project).resolveClassToDescriptor(classOrObject)
return LightClassGenerationSupport.getInstance(project).resolveToDescriptor(classOrObject) as? ClassDescriptor
}
private fun getLightClassData(): OutermostKotlinClassLightClassData {
@@ -262,10 +264,9 @@ open class KtLightClassForExplicitDeclaration(
override fun getQualifiedName(): String = classFqName.asString()
private val _modifierList : PsiModifierList by lazy {
object : KtLightModifierList(this.manager, computeModifiers()) {
override fun getDelegate(): PsiModifierList {
return this@KtLightClassForExplicitDeclaration.getDelegate().modifierList!!
}
object : KtLightModifierListWithExplicitModifiers(this@KtLightClassForExplicitDeclaration, computeModifiers()) {
override val delegate: PsiAnnotationOwner
get() = this@KtLightClassForExplicitDeclaration.getDelegate().modifierList!!
}
}
@@ -384,6 +385,10 @@ open class KtLightClassForExplicitDeclaration(
override fun getElementType(): IStubElementType<out StubElement<*>, *>? = classOrObject.elementType
override fun getStub(): KotlinClassOrObjectStub<out KtClassOrObject>? = classOrObject.stub
private val _lightIdentifier = KtLightIdentifier(this, classOrObject)
override fun getNameIdentifier() = _lightIdentifier
companion object {
private val JAVA_API_STUB = Key.create<CachedValue<WithFileStubAndExtraDiagnostics>>("JAVA_API_STUB")

View File

@@ -16,12 +16,15 @@
package org.jetbrains.kotlin.asJava
import org.jetbrains.kotlin.psi.KtDeclaration
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiNamedElement
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtElement
interface KtLightElement<T : KtDeclaration, D : PsiElement> : PsiNamedElement {
interface KtLightElement<T : KtElement, D : PsiElement> : PsiNamedElement {
fun getOrigin(): T?
fun getDelegate(): D
}
interface KtLightDeclaration<T: KtDeclaration, D: PsiElement>: KtLightElement<T, D>

View File

@@ -25,8 +25,9 @@ import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtEnumEntry
import org.jetbrains.kotlin.psi.KtNamedDeclaration
interface KtLightField : PsiField, KtLightElement<KtDeclaration, PsiField>
interface KtLightField : PsiField, KtLightDeclaration<KtDeclaration, PsiField>
// Copied from com.intellij.psi.impl.light.LightField
sealed class KtLightFieldImpl(
@@ -41,7 +42,9 @@ sealed class KtLightFieldImpl(
override fun getName() = delegate.name
override fun getNameIdentifier() = delegate.nameIdentifier
private val _lightIdentifier = KtLightIdentifier(this, origin as? KtNamedDeclaration)
override fun getNameIdentifier() = _lightIdentifier
override fun getDocComment() = delegate.docComment
@@ -65,7 +68,9 @@ sealed class KtLightFieldImpl(
@Throws(IncorrectOperationException::class)
override fun setName(@NonNls name: String) = throw IncorrectOperationException("Not supported")
override fun getModifierList() = delegate.modifierList
private val _modifierList by lazy { delegate.modifierList?.let { KtLightModifierList(it, this) } }
override fun getModifierList() = _modifierList
override fun hasModifierProperty(@NonNls name: String) = delegate.hasModifierProperty(name)

View File

@@ -0,0 +1,30 @@
/*
* Copyright 2010-2016 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.kotlin.asJava
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiNameIdentifierOwner
import com.intellij.psi.impl.light.LightIdentifier
import org.jetbrains.kotlin.psi.KtNamedDeclaration
class KtLightIdentifier(
private val lightOwner: PsiNameIdentifierOwner,
private val ktDeclaration: KtNamedDeclaration?
) : LightIdentifier(lightOwner.manager, ktDeclaration?.nameIdentifier?.text ?: "") {
override fun getParent() = lightOwner
override fun getTextRange() = ktDeclaration?.nameIdentifier?.textRange ?: TextRange.EMPTY_RANGE
}

View File

@@ -27,7 +27,7 @@ import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind
interface KtLightMethod : PsiMethod, KtLightElement<KtDeclaration, PsiMethod> {
interface KtLightMethod : PsiMethod, KtLightDeclaration<KtDeclaration, PsiMethod> {
val isDelegated: Boolean
}
@@ -108,6 +108,14 @@ sealed class KtLightMethodImpl(
throw IncorrectOperationException(JavaCoreBundle.message("psi.error.attempt.to.edit.class.file"))
}
private val _modifierList by lazy { KtLightModifierList(delegate.modifierList, this) }
override fun getModifierList() = _modifierList
private val _lightIdentifier = KtLightIdentifier(this, origin as? KtNamedDeclaration)
override fun getNameIdentifier() = _lightIdentifier
override fun getParameterList() = paramsList.value
override fun getTypeParameterList() = typeParamsList.value

View File

@@ -1,58 +0,0 @@
/*
* Copyright 2010-2015 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.kotlin.asJava;
import com.intellij.psi.PsiAnnotation;
import com.intellij.psi.PsiAnnotationOwner;
import com.intellij.psi.PsiManager;
import com.intellij.psi.impl.light.LightModifierList;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.idea.KotlinLanguage;
public abstract class KtLightModifierList extends LightModifierList {
public KtLightModifierList(PsiManager psiManager, @NotNull String[] modifiers) {
super(psiManager, KotlinLanguage.INSTANCE, modifiers);
}
public abstract PsiAnnotationOwner getDelegate();
@Override
@NotNull
public PsiAnnotation[] getAnnotations() {
return getDelegate().getAnnotations();
}
@Override
@NotNull
public PsiAnnotation[] getApplicableAnnotations() {
return getDelegate().getApplicableAnnotations();
}
@Override
@Nullable
public PsiAnnotation findAnnotation(@NotNull @NonNls String qualifiedName) {
return getDelegate().findAnnotation(qualifiedName);
}
@Override
@NotNull
public PsiAnnotation addAnnotation(@NotNull @NonNls String qualifiedName) {
return getDelegate().addAnnotation(qualifiedName);
}
}

View File

@@ -0,0 +1,95 @@
/*
* Copyright 2010-2015 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.kotlin.asJava
import com.intellij.psi.*
import com.intellij.psi.impl.light.LightModifierList
import com.intellij.psi.util.CachedValue
import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.CachedValuesManager
import com.intellij.psi.util.PsiModificationTracker
import org.jetbrains.annotations.NonNls
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.psi.KtAnnotationEntry
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.resolve.source.getPsi
abstract class KtLightModifierListWithExplicitModifiers(
private val owner: KtLightElement<*, *>,
modifiers: Array<String>
) : LightModifierList(owner.manager, KotlinLanguage.INSTANCE, *modifiers) {
abstract val delegate: PsiAnnotationOwner
private val _annotations by lazy { computeAnnotations(this, delegate) }
override fun getParent() = owner
override fun getAnnotations(): Array<out PsiAnnotation> = _annotations.value
override fun getApplicableAnnotations() = delegate.applicableAnnotations
override fun findAnnotation(@NonNls qualifiedName: String) = annotations.firstOrNull { it.qualifiedName == qualifiedName }
override fun addAnnotation(@NonNls qualifiedName: String) = delegate.addAnnotation(qualifiedName)
}
class KtLightModifierList(
private val delegate: PsiModifierList,
private val owner: PsiModifierListOwner
): PsiModifierList by delegate {
private val _annotations by lazy { computeAnnotations(this, delegate) }
override fun getAnnotations(): Array<out PsiAnnotation> = _annotations.value
override fun findAnnotation(@NonNls qualifiedName: String) = annotations.firstOrNull { it.qualifiedName == qualifiedName }
override fun addAnnotation(@NonNls qualifiedName: String) = delegate.addAnnotation(qualifiedName)
override fun getParent() = owner
}
internal fun computeAnnotations(lightElement: PsiModifierList,
delegate: PsiAnnotationOwner): CachedValue<Array<out PsiAnnotation>> {
val cacheManager = CachedValuesManager.getManager(lightElement.project)
return cacheManager.createCachedValue<Array<out PsiAnnotation>>(
{
val declaration = (lightElement.parent as? KtLightElement<*, *>)?.getOrigin() as? KtDeclaration
val descriptor = declaration?.let { LightClassGenerationSupport.getInstance(lightElement.project).resolveToDescriptor(it) }
val ktAnnotations = descriptor?.annotations?.getAllAnnotations() ?: emptyList()
var nextIndex = 0
val result = delegate.annotations
.map { clsAnnotation ->
val slice = ktAnnotations.subList(nextIndex, ktAnnotations.size)
val currentIndex = slice.indexOfFirst {
it.annotation.type.constructor.declarationDescriptor?.fqNameUnsafe?.asString() == clsAnnotation.qualifiedName
}
if (currentIndex >= 0) {
nextIndex += currentIndex + 1
val ktAnnotation = slice[currentIndex]
val entry = ktAnnotation.annotation.source.getPsi() as? KtAnnotationEntry
KtLightAnnotation(clsAnnotation, entry, lightElement)
}
else clsAnnotation
}
.toTypedArray()
CachedValueProvider.Result.create(result, PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT)
},
false
)
}

View File

@@ -31,7 +31,7 @@ import org.jetbrains.kotlin.psi.psiUtil.KtPsiUtilKt;
import java.util.List;
public class KtLightParameter extends LightParameter implements KtLightElement<KtParameter, PsiParameter> {
public class KtLightParameter extends LightParameter implements KtLightDeclaration<KtParameter, PsiParameter> {
private static String getName(PsiParameter delegate, int index) {
String name = delegate.getName();
return name != null ? name : "p" + index;
@@ -49,7 +49,7 @@ public class KtLightParameter extends LightParameter implements KtLightElement<K
this.index = index;
this.method = method;
this.modifierList = new KtLightModifierList(method.getManager(), ArrayUtil.EMPTY_STRING_ARRAY) {
this.modifierList = new KtLightModifierListWithExplicitModifiers(this, ArrayUtil.EMPTY_STRING_ARRAY) {
@Override
public PsiAnnotationOwner getDelegate() {
return delegate.getModifierList();

View File

@@ -27,7 +27,7 @@ import org.jetbrains.kotlin.psi.KtTypeParameter;
import org.jetbrains.kotlin.psi.KtTypeParameterListOwner;
public class KtLightTypeParameter
extends AbstractLightClass implements PsiTypeParameter, KtLightElement<KtTypeParameter, PsiTypeParameter> {
extends AbstractLightClass implements PsiTypeParameter, KtLightDeclaration<KtTypeParameter, PsiTypeParameter> {
private final PsiTypeParameterListOwner owner;
private final int index;
private final String name;

View File

@@ -123,7 +123,9 @@ public abstract class KtWrappingLightClass extends AbstractLightClass implements
@Override
public PsiField fun(PsiField field) {
LightMemberOrigin origin = ClsWrapperStubPsiFactory.getMemberOrigin(field);
return KtLightFieldImpl.Factory.create(origin != null ? origin.getOriginalElement() : null, field, KtWrappingLightClass.this);
return KtLightFieldImpl.Factory.create(origin != null ? origin.getOriginalElement() : null,
field,
KtWrappingLightClass.this);
}
});
}

View File

@@ -23,8 +23,10 @@ import com.intellij.psi.search.GlobalSearchScope;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.psi.KtClassOrObject;
import org.jetbrains.kotlin.psi.KtDeclaration;
import org.jetbrains.kotlin.psi.KtFile;
import java.util.Collection;
@@ -68,7 +70,7 @@ public abstract class LightClassGenerationSupport {
public abstract KtLightClass getLightClass(@NotNull KtClassOrObject classOrObject);
@Nullable
public abstract ClassDescriptor resolveClassToDescriptor(@NotNull KtClassOrObject classOrObject);
public abstract DeclarationDescriptor resolveToDescriptor(@NotNull KtDeclaration declaration);
@NotNull
public abstract Collection<PsiClass> getFacadeClasses(@NotNull FqName facadeFqName, @NotNull GlobalSearchScope scope);

View File

@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.asJava
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.psi.KtAnnotationEntry
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind
@@ -40,18 +41,19 @@ fun JvmDeclarationOrigin.toLightMemberOrigin(): LightElementOrigin {
val originalElement = element
return when (originalElement) {
is KtDeclaration -> LightMemberOrigin(originalElement, originKind)
is KtAnnotationEntry -> DefaultLightElementOrigin(originalElement)
else -> LightElementOrigin.None
}
}
data class LightMemberOrigin(override val originalElement: KtDeclaration, override val originKind: JvmDeclarationOriginKind) : LightElementOrigin
data class LightClassOrigin(override val originalElement: PsiElement?) : LightElementOrigin {
data class DefaultLightElementOrigin(override val originalElement: PsiElement?) : LightElementOrigin {
override val originKind: JvmDeclarationOriginKind? get() = null
}
fun PsiElement?.toLightClassOrigin(): LightElementOrigin {
return if (this != null) LightClassOrigin(this) else LightElementOrigin.None
return if (this != null) DefaultLightElementOrigin(this) else LightElementOrigin.None
}
fun LightMemberOrigin.copy() = LightMemberOrigin(originalElement.copy() as KtDeclaration, originKind)

View File

@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.isExtensionDeclaration
import org.jetbrains.kotlin.utils.addToStdlib.singletonList
import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList
@@ -126,3 +127,9 @@ private fun isNonAbstractMember(member: KtDeclaration?): Boolean {
private val DEFAULT_IMPLS_CLASS_NAME = Name.identifier(JvmAbi.DEFAULT_IMPLS_CLASS_NAME)
fun FqName.defaultImplsChild() = child(DEFAULT_IMPLS_CLASS_NAME)
fun KtAnnotationEntry.toLightAnnotation(): PsiAnnotation? {
val ktDeclaration = getStrictParentOfType<KtModifierList>()?.parent as? KtDeclaration ?: return null
val lightElement = ktDeclaration.toLightElements().firstOrNull() as? PsiModifierListOwner ?: return null
return lightElement.modifierList?.annotations?.firstOrNull { it is KtLightAnnotation && it.getOrigin() == this }
}

View File

@@ -1 +1 @@
@Foo(s = "...")
@Foo("...")

View File

@@ -29,6 +29,7 @@ import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.asJava.*
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName
import org.jetbrains.kotlin.idea.decompiler.classFile.KtClsFile
@@ -192,9 +193,9 @@ class IDELightClassGenerationSupport(private val project: Project) : LightClassG
return KotlinFileFacadeFqNameIndex.INSTANCE.get(facadeFqName.asString(), project, scope)
}
override fun resolveClassToDescriptor(classOrObject: KtClassOrObject): ClassDescriptor? {
override fun resolveToDescriptor(declaration: KtDeclaration): DeclarationDescriptor? {
try {
return classOrObject.resolveToDescriptor() as ClassDescriptor
return declaration.resolveToDescriptor()
}
catch (e: NoDescriptorForDeclarationException) {
return null

View File

@@ -22,7 +22,7 @@ import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.util.text.StringUtil
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiManager
import org.jetbrains.kotlin.asJava.KtLightElement
import org.jetbrains.kotlin.asJava.KtLightDeclaration
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
@@ -92,7 +92,7 @@ class KotlinQuickDocumentationProvider : AbstractDocumentationProvider() {
if (element is KtDeclaration) {
return renderKotlinDeclaration(element, quickNavigation)
}
else if (element is KtLightElement<*, *>) {
else if (element is KtLightDeclaration<*, *>) {
val origin = element.getOrigin() ?: return null
return renderKotlinDeclaration(origin, quickNavigation)
}