Remove 173 bunch files
This commit is contained in:
-142
@@ -1,142 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.builder
|
||||
|
||||
import com.intellij.openapi.components.ServiceManager
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.progress.ProcessCanceledException
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.SystemInfo
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.ClassFileViewProvider
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiManager
|
||||
import com.intellij.psi.impl.compiled.ClsFileImpl
|
||||
import com.intellij.psi.impl.java.stubs.PsiJavaFileStub
|
||||
import com.intellij.psi.impl.java.stubs.impl.PsiJavaFileStubImpl
|
||||
import com.intellij.psi.impl.source.tree.TreeElement
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.config.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
|
||||
import java.lang.StringBuilder
|
||||
|
||||
data class LightClassBuilderResult(val stub: PsiJavaFileStub, val bindingContext: BindingContext, val diagnostics: Diagnostics)
|
||||
|
||||
fun buildLightClass(
|
||||
packageFqName: FqName,
|
||||
files: Collection<KtFile>,
|
||||
generateClassFilter: GenerationState.GenerateClassFilter,
|
||||
context: LightClassConstructionContext,
|
||||
generate: (state: GenerationState, files: Collection<KtFile>) -> Unit
|
||||
): LightClassBuilderResult {
|
||||
val project = files.first().project
|
||||
|
||||
try {
|
||||
val classBuilderFactory = KotlinLightClassBuilderFactory(createJavaFileStub(project, packageFqName, files))
|
||||
val state = GenerationState.Builder(
|
||||
project,
|
||||
classBuilderFactory,
|
||||
context.module,
|
||||
context.bindingContext,
|
||||
files.toList(),
|
||||
context.languageVersionSettings?.let {
|
||||
CompilerConfiguration().apply {
|
||||
languageVersionSettings = it
|
||||
isReadOnly = true
|
||||
}
|
||||
} ?: CompilerConfiguration.EMPTY
|
||||
).generateDeclaredClassFilter(generateClassFilter).wantsDiagnostics(false).build()
|
||||
state.beforeCompile()
|
||||
|
||||
generate(state, files)
|
||||
|
||||
val javaFileStub = classBuilderFactory.result()
|
||||
|
||||
ServiceManager.getService(project, StubComputationTracker::class.java)?.onStubComputed(javaFileStub, context)
|
||||
return LightClassBuilderResult(javaFileStub, context.bindingContext, state.collectedExtraJvmDiagnostics)
|
||||
}
|
||||
catch (e: ProcessCanceledException) {
|
||||
throw e
|
||||
}
|
||||
catch (e: RuntimeException) {
|
||||
logErrorWithOSInfo(e, packageFqName, null)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
private fun createJavaFileStub(project: Project, packageFqName: FqName, files: Collection<KtFile>): PsiJavaFileStub {
|
||||
val javaFileStub = PsiJavaFileStubImpl(packageFqName.asString(), /*compiled = */true)
|
||||
javaFileStub.psiFactory = ClsWrapperStubPsiFactory.INSTANCE
|
||||
|
||||
val manager = PsiManager.getInstance(project)
|
||||
|
||||
val virtualFile = getRepresentativeVirtualFile(files)
|
||||
val fakeFile = object : ClsFileImpl(ClassFileViewProvider(manager, virtualFile)) {
|
||||
override fun getStub() = javaFileStub
|
||||
|
||||
override fun getPackageName() = packageFqName.asString()
|
||||
|
||||
override fun isPhysical() = false
|
||||
|
||||
override fun appendMirrorText(indentLevel: Int, buffer: StringBuilder) {
|
||||
if (files.size == 1) {
|
||||
LOG.error("Mirror text should never be calculated for light classes generated from a single file")
|
||||
}
|
||||
super.appendMirrorText(indentLevel, buffer)
|
||||
}
|
||||
|
||||
|
||||
override fun setMirror(element: TreeElement) {
|
||||
if (files.size == 1) {
|
||||
LOG.error("Mirror element should never be set for light classes generated from a single file")
|
||||
}
|
||||
super.setMirror(element)
|
||||
}
|
||||
|
||||
override fun getMirror(): PsiElement {
|
||||
if (files.size == 1) {
|
||||
LOG.error("Mirror element should never be calculated for light classes generated from a single file")
|
||||
}
|
||||
return super.getMirror()
|
||||
}
|
||||
|
||||
override fun getText(): String {
|
||||
return files.singleOrNull()?.text ?: super.getText()
|
||||
}
|
||||
}
|
||||
|
||||
javaFileStub.psi = fakeFile
|
||||
return javaFileStub
|
||||
}
|
||||
|
||||
private fun getRepresentativeVirtualFile(files: Collection<KtFile>): VirtualFile {
|
||||
return files.first().viewProvider.virtualFile
|
||||
}
|
||||
|
||||
private fun logErrorWithOSInfo(cause: Throwable?, fqName: FqName, virtualFile: VirtualFile?) {
|
||||
val path = if (virtualFile == null) "<null>" else virtualFile.path
|
||||
LOG.error(
|
||||
"Could not generate LightClass for $fqName declared in $path\n" +
|
||||
"System: ${SystemInfo.OS_NAME} ${SystemInfo.OS_VERSION} Java Runtime: ${SystemInfo.JAVA_RUNTIME_VERSION}",
|
||||
cause
|
||||
)
|
||||
}
|
||||
|
||||
private val LOG = Logger.getInstance(LightClassBuilderResult::class.java)
|
||||
-86
@@ -1,86 +0,0 @@
|
||||
/*
|
||||
* 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.elements
|
||||
|
||||
import com.intellij.pom.java.LanguageLevel
|
||||
import com.intellij.psi.ClassFileViewProvider
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiElementVisitor
|
||||
import com.intellij.psi.impl.compiled.ClsFileImpl
|
||||
import com.intellij.psi.stubs.PsiClassHolderFileStub
|
||||
import org.jetbrains.kotlin.asJava.classes.KtLightClass
|
||||
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
|
||||
import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
|
||||
open class FakeFileForLightClass(
|
||||
val ktFile: KtFile,
|
||||
private val lightClass: () -> KtLightClass,
|
||||
private val stub: () -> PsiClassHolderFileStub<*>,
|
||||
private val packageFqName: FqName = ktFile.packageFqName
|
||||
) : ClsFileImpl(ClassFileViewProvider(ktFile.manager, ktFile.virtualFile ?:
|
||||
ktFile.originalFile.virtualFile ?:
|
||||
ktFile.viewProvider.virtualFile)) {
|
||||
override fun getPackageName() = packageFqName.asString()
|
||||
|
||||
override fun getStub() = stub()
|
||||
|
||||
override fun getClasses() = arrayOf(lightClass())
|
||||
|
||||
override fun getNavigationElement() = ktFile
|
||||
|
||||
override fun accept(visitor: PsiElementVisitor) {
|
||||
// Prevent access to compiled PSI
|
||||
// TODO: More complex traversal logic may be implemented when necessary
|
||||
}
|
||||
|
||||
// this should be equal to current compiler target language level
|
||||
override fun getLanguageLevel() = LanguageLevel.JDK_1_6
|
||||
|
||||
override fun hashCode(): Int {
|
||||
val thisClass = lightClass()
|
||||
if (thisClass is KtLightClassForSourceDeclaration) return ktFile.hashCode()
|
||||
return thisClass.hashCode()
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is FakeFileForLightClass) return false
|
||||
val thisClass = lightClass()
|
||||
val anotherClass = other.lightClass()
|
||||
|
||||
if (thisClass is KtLightClassForSourceDeclaration) {
|
||||
return anotherClass is KtLightClassForSourceDeclaration && ktFile == other.ktFile
|
||||
}
|
||||
|
||||
return thisClass == anotherClass
|
||||
}
|
||||
|
||||
override fun isEquivalentTo(another: PsiElement?) = this == another
|
||||
|
||||
override fun setPackageName(packageName: String) {
|
||||
if (lightClass() is KtLightClassForFacade) {
|
||||
ktFile.packageDirective?.fqName = FqName(packageName)
|
||||
}
|
||||
else {
|
||||
super.setPackageName(packageName)
|
||||
}
|
||||
}
|
||||
|
||||
override fun isPhysical() = false
|
||||
}
|
||||
-135
@@ -1,135 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.asJava.elements
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.impl.LanguageConstantExpressionEvaluator
|
||||
import com.intellij.psi.impl.light.LightIdentifier
|
||||
import com.intellij.psi.impl.light.LightTypeElement
|
||||
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
|
||||
import org.jetbrains.kotlin.asJava.classes.lazyPub
|
||||
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
|
||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.constants.KClassValue
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
class KtLightPsiArrayInitializerMemberValue(
|
||||
override val kotlinOrigin: KtElement,
|
||||
val lightParent: PsiElement,
|
||||
private val arguments: (KtLightPsiArrayInitializerMemberValue) -> List<PsiAnnotationMemberValue>
|
||||
) : KtLightElementBase(lightParent), PsiArrayInitializerMemberValue {
|
||||
override fun getInitializers(): Array<PsiAnnotationMemberValue> = arguments(this).toTypedArray()
|
||||
|
||||
override fun getParent(): PsiElement = lightParent
|
||||
|
||||
override fun isPhysical(): Boolean = true
|
||||
}
|
||||
|
||||
open class KtLightPsiLiteral(
|
||||
override val kotlinOrigin: KtExpression,
|
||||
val lightParent: PsiElement
|
||||
) : KtLightElementBase(lightParent), PsiLiteralExpression {
|
||||
|
||||
override fun getValue(): Any? =
|
||||
LanguageConstantExpressionEvaluator.INSTANCE.forLanguage(kotlinOrigin.language)?.computeConstantExpression(this, false)
|
||||
|
||||
override fun getType(): PsiType? {
|
||||
val bindingContext = LightClassGenerationSupport.getInstance(this.project).analyze(kotlinOrigin)
|
||||
val kotlinType = bindingContext[BindingContext.EXPECTED_EXPRESSION_TYPE, kotlinOrigin] ?: return null
|
||||
val typeFqName = kotlinType.constructor.declarationDescriptor?.fqNameSafe?.asString() ?: return null
|
||||
return psiType(typeFqName, kotlinOrigin)
|
||||
}
|
||||
|
||||
override fun getParent(): PsiElement = lightParent
|
||||
|
||||
override fun isPhysical(): Boolean = true
|
||||
|
||||
override fun replace(newElement: PsiElement): PsiElement {
|
||||
val value = (newElement as? PsiLiteral)?.value as? String ?: return this
|
||||
kotlinOrigin.replace(KtPsiFactory(this).createExpression("\"${StringUtil.escapeStringCharacters(value)}\""))
|
||||
return this
|
||||
}
|
||||
|
||||
override fun getReference(): PsiReference? = references.singleOrNull()
|
||||
override fun getReferences(): Array<out PsiReference> = kotlinOrigin.references
|
||||
}
|
||||
|
||||
class KtLightPsiClassObjectAccessExpression(override val kotlinOrigin: KtClassLiteralExpression, lightParent: PsiElement) :
|
||||
KtLightPsiLiteral(kotlinOrigin, lightParent), PsiClassObjectAccessExpression {
|
||||
override fun getType(): PsiType {
|
||||
val bindingContext = LightClassGenerationSupport.getInstance(this.project).analyze(kotlinOrigin)
|
||||
val (classId, arrayDimensions) = bindingContext[BindingContext.COMPILE_TIME_VALUE, kotlinOrigin]
|
||||
?.toConstantValue(TypeUtils.NO_EXPECTED_TYPE)?.safeAs<KClassValue>()?.value ?: return PsiType.VOID
|
||||
var type = psiType(classId.asSingleFqName().asString(), kotlinOrigin, boxPrimitiveType = arrayDimensions > 0) ?: return PsiType.VOID
|
||||
repeat(arrayDimensions) {
|
||||
type = type.createArrayType()
|
||||
}
|
||||
return type
|
||||
}
|
||||
|
||||
override fun getOperand(): PsiTypeElement = LightTypeElement(kotlinOrigin.manager, type)
|
||||
}
|
||||
|
||||
internal fun psiType(kotlinFqName: String, context: PsiElement, boxPrimitiveType: Boolean = false): PsiType {
|
||||
if (!boxPrimitiveType) {
|
||||
when (kotlinFqName) {
|
||||
"kotlin.Int" -> return PsiType.INT
|
||||
"kotlin.Long" -> return PsiType.LONG
|
||||
"kotlin.Short" -> return PsiType.SHORT
|
||||
"kotlin.Boolean" -> return PsiType.BOOLEAN
|
||||
"kotlin.Byte" -> return PsiType.BYTE
|
||||
"kotlin.Char" -> return PsiType.CHAR
|
||||
"kotlin.Double" -> return PsiType.DOUBLE
|
||||
"kotlin.Float" -> return PsiType.FLOAT
|
||||
}
|
||||
}
|
||||
when (kotlinFqName) {
|
||||
"kotlin.IntArray" -> return PsiType.INT.createArrayType()
|
||||
"kotlin.LongArray" -> return PsiType.LONG.createArrayType()
|
||||
"kotlin.ShortArray" -> return PsiType.SHORT.createArrayType()
|
||||
"kotlin.BooleanArray" -> return PsiType.BOOLEAN.createArrayType()
|
||||
"kotlin.ByteArray" -> return PsiType.BYTE.createArrayType()
|
||||
"kotlin.CharArray" -> return PsiType.CHAR.createArrayType()
|
||||
"kotlin.DoubleArray" -> return PsiType.DOUBLE.createArrayType()
|
||||
"kotlin.FloatArray" -> return PsiType.FLOAT.createArrayType()
|
||||
}
|
||||
val javaFqName = JavaToKotlinClassMap.mapKotlinToJava(FqNameUnsafe(kotlinFqName))?.asSingleFqName()?.asString() ?: kotlinFqName
|
||||
return PsiType.getTypeByName(javaFqName, context.project, context.resolveScope)
|
||||
}
|
||||
|
||||
class KtLightPsiNameValuePair private constructor(
|
||||
override val kotlinOrigin: KtElement,
|
||||
val valueArgument: KtValueArgument,
|
||||
lightParent: PsiElement,
|
||||
private val argument: (KtLightPsiNameValuePair) -> PsiAnnotationMemberValue?
|
||||
) : KtLightElementBase(lightParent),
|
||||
PsiNameValuePair {
|
||||
|
||||
constructor(
|
||||
valueArgument: KtValueArgument,
|
||||
lightParent: PsiElement,
|
||||
argument: (KtLightPsiNameValuePair) -> PsiAnnotationMemberValue?
|
||||
) : this(valueArgument.asElement(), valueArgument, lightParent, argument)
|
||||
|
||||
override fun setValue(newValue: PsiAnnotationMemberValue): PsiAnnotationMemberValue =
|
||||
throw UnsupportedOperationException("can't modify KtLightPsiNameValuePair")
|
||||
|
||||
override fun getNameIdentifier(): PsiIdentifier? = LightIdentifier(kotlinOrigin.manager, valueArgument.name)
|
||||
|
||||
override fun getName(): String? = valueArgument.getArgumentName()?.asName?.asString()
|
||||
|
||||
private val _value: PsiAnnotationMemberValue? by lazyPub { argument(this) }
|
||||
|
||||
override fun getValue(): PsiAnnotationMemberValue? = _value
|
||||
|
||||
override fun getLiteralValue(): String? = (getValue() as? PsiLiteralExpression)?.value?.toString()
|
||||
|
||||
}
|
||||
-425
@@ -1,425 +0,0 @@
|
||||
/*
|
||||
* 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.elements
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.annotations.NotNull
|
||||
import org.jetbrains.annotations.Nullable
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
|
||||
import org.jetbrains.kotlin.asJava.classes.cannotModify
|
||||
import org.jetbrains.kotlin.asJava.classes.lazyPub
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaClassConstructorDescriptor
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.CompileTimeConstantUtils
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getType
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.declaresOrInheritsDefaultValue
|
||||
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.typeUtil.TypeNullability
|
||||
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
|
||||
import org.jetbrains.kotlin.types.typeUtil.isUnit
|
||||
import org.jetbrains.kotlin.types.typeUtil.nullability
|
||||
|
||||
private val LOG = Logger.getInstance("#org.jetbrains.kotlin.asJava.elements.lightAnnotations")
|
||||
|
||||
abstract class KtLightAbstractAnnotation(parent: PsiElement, computeDelegate: () -> PsiAnnotation) :
|
||||
KtLightElementBase(parent), PsiAnnotation, KtLightElement<KtCallElement, PsiAnnotation> {
|
||||
|
||||
private val _clsDelegate: PsiAnnotation by lazyPub(computeDelegate)
|
||||
|
||||
override val clsDelegate: PsiAnnotation
|
||||
get() {
|
||||
if (!accessAnnotationsClsDelegateIsAllowed && ApplicationManager.getApplication().isUnitTestMode && this !is KtLightNonSourceAnnotation)
|
||||
LOG.error("KtLightAbstractAnnotation clsDelegate requested for ${this.javaClass}")
|
||||
return _clsDelegate
|
||||
}
|
||||
|
||||
override fun getNameReferenceElement() = clsDelegate.nameReferenceElement
|
||||
|
||||
override fun getOwner() = parent as? PsiAnnotationOwner
|
||||
|
||||
override fun getMetaData() = clsDelegate.metaData
|
||||
|
||||
override fun getParameterList() = clsDelegate.parameterList
|
||||
|
||||
override fun canNavigate(): Boolean = super<KtLightElementBase>.canNavigate()
|
||||
|
||||
override fun canNavigateToSource(): Boolean = super<KtLightElementBase>.canNavigateToSource()
|
||||
|
||||
override fun navigate(requestFocus: Boolean) = super<KtLightElementBase>.navigate(requestFocus)
|
||||
|
||||
open fun fqNameMatches(fqName: String): Boolean = qualifiedName == fqName
|
||||
}
|
||||
|
||||
class KtLightAnnotationForSourceEntry(
|
||||
private val qualifiedName: String,
|
||||
override val kotlinOrigin: KtCallElement,
|
||||
parent: PsiElement,
|
||||
computeDelegate: () -> PsiAnnotation
|
||||
) : KtLightAbstractAnnotation(parent, computeDelegate) {
|
||||
|
||||
override fun getQualifiedName() = qualifiedName
|
||||
|
||||
override fun isPhysical() = true
|
||||
|
||||
override fun getName(): String? = null
|
||||
|
||||
override fun findAttributeValue(name: String?) = getAttributeValue(name, true)
|
||||
|
||||
override fun findDeclaredAttributeValue(name: String?): PsiAnnotationMemberValue? = getAttributeValue(name, false)
|
||||
|
||||
private fun getCallEntry(name: String): MutableMap.MutableEntry<ValueParameterDescriptor, ResolvedValueArgument>? {
|
||||
val resolvedCall = kotlinOrigin.getResolvedCall() ?: return null
|
||||
return resolvedCall.valueArguments.entries.find { (param, _) -> param.name.asString() == name } ?: return null
|
||||
}
|
||||
|
||||
private fun getAttributeValue(name: String?, useDefault: Boolean): PsiAnnotationMemberValue? {
|
||||
val name = name ?: "value"
|
||||
val callEntry = getCallEntry(name) ?: return null
|
||||
|
||||
val valueArgument = callEntry.value.arguments.firstOrNull()
|
||||
if (valueArgument != null) {
|
||||
ktLightAnnotationParameterList.attributes.find { (it as KtLightPsiNameValuePair).valueArgument === valueArgument }?.let {
|
||||
return it.value
|
||||
}
|
||||
}
|
||||
|
||||
if (useDefault && callEntry.key.declaresOrInheritsDefaultValue()) {
|
||||
val psiElement = callEntry.key.source.getPsi()
|
||||
when (psiElement) {
|
||||
is KtParameter ->
|
||||
return psiElement.defaultValue?.let { convertToLightAnnotationMemberValue(this, it) }
|
||||
is PsiAnnotationMethod ->
|
||||
return psiElement.defaultValue
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
override fun getNameReferenceElement(): PsiJavaCodeReferenceElement? = KtLightPsiJavaCodeReferenceElement(
|
||||
kotlinOrigin.navigationElement,
|
||||
{
|
||||
(kotlinOrigin as? KtAnnotationEntry)?.typeReference?.reference
|
||||
?: (kotlinOrigin.calleeExpression?.nameReference)?.references?.firstOrNull()
|
||||
},
|
||||
{ super.getNameReferenceElement() }
|
||||
)
|
||||
|
||||
|
||||
private val ktLightAnnotationParameterList by lazyPub { KtLightAnnotationParameterList() }
|
||||
|
||||
override fun getParameterList(): PsiAnnotationParameterList = ktLightAnnotationParameterList
|
||||
|
||||
inner class KtLightAnnotationParameterList() : KtLightElementBase(this),
|
||||
PsiAnnotationParameterList {
|
||||
override val kotlinOrigin: KtElement? get() = null
|
||||
|
||||
private val _attributes: Array<PsiNameValuePair> by lazyPub {
|
||||
this@KtLightAnnotationForSourceEntry.kotlinOrigin.valueArguments.map { makeLightPsiNameValuePair(it as KtValueArgument) }
|
||||
.toTypedArray<PsiNameValuePair>()
|
||||
}
|
||||
|
||||
private fun makeArrayInitializerIfExpected(pair: KtLightPsiNameValuePair): PsiAnnotationMemberValue? {
|
||||
val valueArgument = pair.valueArgument
|
||||
val name = valueArgument.name ?: "value"
|
||||
val callEntry = getCallEntry(name) ?: return null
|
||||
|
||||
val valueArguments = callEntry.value.arguments
|
||||
val argument = valueArguments.firstOrNull()?.getArgumentExpression() ?: return null
|
||||
|
||||
if (!callEntry.key.type.let { KotlinBuiltIns.isArrayOrPrimitiveArray(it) }) return null
|
||||
|
||||
if (argument !is KtStringTemplateExpression &&
|
||||
argument !is KtConstantExpression &&
|
||||
argument !is KtClassLiteralExpression &&
|
||||
getAnnotationName(argument) == null
|
||||
) {
|
||||
return null
|
||||
}
|
||||
|
||||
val parent = PsiTreeUtil.findCommonParent(valueArguments.map { it.getArgumentExpression() }) as KtElement
|
||||
return KtLightPsiArrayInitializerMemberValue(parent, pair) { self ->
|
||||
valueArguments.mapNotNull {
|
||||
it.getArgumentExpression()?.let { convertToLightAnnotationMemberValue(self, it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun makeLightPsiNameValuePair(valueArgument: KtValueArgument) = KtLightPsiNameValuePair(valueArgument, this) { self ->
|
||||
makeArrayInitializerIfExpected(self)
|
||||
?: self.valueArgument.getArgumentExpression()?.let { convertToLightAnnotationMemberValue(self, it) }
|
||||
}
|
||||
|
||||
override fun getAttributes(): Array<PsiNameValuePair> = _attributes
|
||||
|
||||
}
|
||||
|
||||
|
||||
override fun delete() = kotlinOrigin.delete()
|
||||
|
||||
override fun toString() = "@$qualifiedName"
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other == null || other::class.java != this::class.java) return false
|
||||
return kotlinOrigin == (other as KtLightAnnotationForSourceEntry).kotlinOrigin
|
||||
}
|
||||
|
||||
override fun hashCode() = kotlinOrigin.hashCode()
|
||||
|
||||
override fun <T : PsiAnnotationMemberValue?> setDeclaredAttributeValue(attributeName: String?, value: T?) = cannotModify()
|
||||
}
|
||||
|
||||
class KtLightNonSourceAnnotation(
|
||||
parent: PsiElement, clsDelegate: PsiAnnotation
|
||||
) : KtLightAbstractAnnotation(parent, { clsDelegate }) {
|
||||
override val kotlinOrigin: KtAnnotationEntry? get() = null
|
||||
override fun getQualifiedName() = kotlinOrigin?.name ?: clsDelegate.qualifiedName
|
||||
override fun <T : PsiAnnotationMemberValue?> setDeclaredAttributeValue(attributeName: String?, value: T?) = cannotModify()
|
||||
override fun findAttributeValue(attributeName: String?) = clsDelegate.findAttributeValue(attributeName)
|
||||
override fun findDeclaredAttributeValue(attributeName: String?) = clsDelegate.findDeclaredAttributeValue(attributeName)
|
||||
}
|
||||
|
||||
class KtLightNonExistentAnnotation(parent: KtLightElement<*, *>) : KtLightElementBase(parent), PsiAnnotation {
|
||||
override val kotlinOrigin get() = null
|
||||
override fun toString() = this.javaClass.name
|
||||
|
||||
override fun <T : PsiAnnotationMemberValue?> setDeclaredAttributeValue(attributeName: String?, value: T?) = cannotModify()
|
||||
|
||||
override fun getNameReferenceElement() = null
|
||||
override fun findAttributeValue(attributeName: String?) = null
|
||||
override fun getQualifiedName() = null
|
||||
override fun getOwner() = parent as? PsiAnnotationOwner
|
||||
override fun findDeclaredAttributeValue(attributeName: String?) = null
|
||||
override fun getMetaData() = null
|
||||
override fun getParameterList() = KtLightEmptyAnnotationParameterList(this)
|
||||
|
||||
override fun canNavigate(): Boolean = super<KtLightElementBase>.canNavigate()
|
||||
|
||||
override fun canNavigateToSource(): Boolean = super<KtLightElementBase>.canNavigateToSource()
|
||||
|
||||
override fun navigate(requestFocus: Boolean) = super<KtLightElementBase>.navigate(requestFocus)
|
||||
}
|
||||
|
||||
class KtLightEmptyAnnotationParameterList(parent: PsiElement) : KtLightElementBase(parent), PsiAnnotationParameterList {
|
||||
override val kotlinOrigin get() = null
|
||||
override fun getAttributes(): Array<PsiNameValuePair> = emptyArray()
|
||||
}
|
||||
|
||||
open class KtLightNullabilityAnnotation<D : KtLightElement<*, PsiModifierListOwner>>(val member: D, parent: PsiElement) :
|
||||
KtLightAbstractAnnotation(parent, {
|
||||
// searching for last because nullability annotations are generated after backend generates source annotations
|
||||
getClsNullabilityAnnotation(member) ?: KtLightNonExistentAnnotation(member)
|
||||
}) {
|
||||
override fun fqNameMatches(fqName: String): Boolean {
|
||||
if (!isNullabilityAnnotation(fqName)) return false
|
||||
|
||||
return super.fqNameMatches(fqName)
|
||||
}
|
||||
|
||||
override val kotlinOrigin get() = null
|
||||
override fun <T : PsiAnnotationMemberValue?> setDeclaredAttributeValue(attributeName: String?, value: T?) = cannotModify()
|
||||
|
||||
override fun findAttributeValue(attributeName: String?) = null
|
||||
|
||||
override fun getQualifiedName(): String? {
|
||||
val annotatedElement = member.takeIf(::isFromSources)?.kotlinOrigin
|
||||
?: // it is out of our hands
|
||||
return getClsNullabilityAnnotation(member)?.qualifiedName
|
||||
|
||||
// all data-class generated members are not-null
|
||||
if (annotatedElement is KtClass && annotatedElement.isData()) return NotNull::class.java.name
|
||||
|
||||
if (annotatedElement is KtParameter) {
|
||||
if (annotatedElement.containingClassOrObject?.isAnnotation() == true) return null
|
||||
}
|
||||
|
||||
// don't annotate property setters
|
||||
if (annotatedElement is KtValVarKeywordOwner && member is KtLightMethod && member.returnType == PsiType.VOID) return null
|
||||
|
||||
val kotlinType = getTargetType(annotatedElement) ?: return null
|
||||
if (KotlinBuiltIns.isPrimitiveType(kotlinType) && (annotatedElement as? KtParameter)?.isVarArg != true) {
|
||||
// no need to annotate them explicitly except the case when overriding reference-type makes it non-primitive for Jvm
|
||||
if (!(annotatedElement is KtCallableDeclaration && annotatedElement.hasModifier(KtTokens.OVERRIDE_KEYWORD))) return null
|
||||
|
||||
val overriddenDescriptors =
|
||||
(annotatedElement.analyze()[BindingContext.DECLARATION_TO_DESCRIPTOR, annotatedElement] as? CallableMemberDescriptor)?.overriddenDescriptors
|
||||
if (overriddenDescriptors?.all { it.returnType == kotlinType } == true) return null
|
||||
}
|
||||
if (kotlinType.isUnit() && (annotatedElement !is KtValVarKeywordOwner)) return null // not annotate unit-functions
|
||||
if (kotlinType.isTypeParameter()) {
|
||||
if (!TypeUtils.hasNullableSuperType(kotlinType)) return NotNull::class.java.name
|
||||
if (!kotlinType.isMarkedNullable) return null
|
||||
}
|
||||
|
||||
val nullability = kotlinType.nullability()
|
||||
return when (nullability) {
|
||||
TypeNullability.NOT_NULL -> NotNull::class.java.name
|
||||
TypeNullability.NULLABLE -> Nullable::class.java.name
|
||||
TypeNullability.FLEXIBLE -> null
|
||||
}
|
||||
}
|
||||
|
||||
internal fun KtTypeReference.getType(): KotlinType? = analyze()[BindingContext.TYPE, this]
|
||||
|
||||
private fun getTargetType(annotatedElement: PsiElement): KotlinType? {
|
||||
if (annotatedElement is KtTypeReference) {
|
||||
annotatedElement.getType()?.let { return it }
|
||||
}
|
||||
if (annotatedElement is KtCallableDeclaration) {
|
||||
annotatedElement.typeReference?.getType()?.let { return it }
|
||||
}
|
||||
if (annotatedElement is KtNamedFunction) {
|
||||
annotatedElement.bodyExpression?.let { it.getType(it.analyze()) }?.let { return it }
|
||||
}
|
||||
if (annotatedElement is KtProperty) {
|
||||
annotatedElement.initializer?.let { it.getType(it.analyze()) }?.let { return it }
|
||||
annotatedElement.delegateExpression?.let { it.getType(it.analyze())?.arguments?.firstOrNull()?.type }?.let { return it }
|
||||
}
|
||||
annotatedElement.getParentOfType<KtProperty>(false)?.let {
|
||||
it.typeReference?.getType() ?: it.initializer?.let { it.getType(it.analyze()) }
|
||||
}?.let { return it }
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
override fun getNameReferenceElement(): PsiJavaCodeReferenceElement? = null
|
||||
|
||||
override fun getParameterList(): PsiAnnotationParameterList = KtLightEmptyAnnotationParameterList(this)
|
||||
|
||||
override fun findDeclaredAttributeValue(attributeName: String?) = null
|
||||
}
|
||||
|
||||
private fun getClsNullabilityAnnotation(member: KtLightElement<*, PsiModifierListOwner>): PsiAnnotation? {
|
||||
if (!accessAnnotationsClsDelegateIsAllowed && ApplicationManager.getApplication().isUnitTestMode && isFromSources(member) && member.kotlinOrigin != null)
|
||||
LOG.error("nullability should be retrieved from `kotlinOrigin`")
|
||||
return member.clsDelegate.modifierList?.annotations?.findLast {
|
||||
isNullabilityAnnotation(it.qualifiedName)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun isNullabilityAnnotation(qualifiedName: String?) = qualifiedName in backendNullabilityAnnotations
|
||||
|
||||
private val backendNullabilityAnnotations = arrayOf(Nullable::class.java.name, NotNull::class.java.name)
|
||||
|
||||
private fun KtElement.analyze(): BindingContext = LightClassGenerationSupport.getInstance(this.project).analyze(this)
|
||||
|
||||
private fun KtElement.getResolvedCall(): ResolvedCall<out CallableDescriptor>? {
|
||||
if (!isValid) return null
|
||||
val context = analyze()
|
||||
return this.getResolvedCall(context)
|
||||
}
|
||||
|
||||
fun convertToLightAnnotationMemberValue(lightParent: PsiElement, argument: KtExpression): PsiAnnotationMemberValue {
|
||||
val argument = unwrapCall(argument)
|
||||
when (argument) {
|
||||
is KtClassLiteralExpression -> {
|
||||
return KtLightPsiClassObjectAccessExpression(argument, lightParent)
|
||||
}
|
||||
is KtStringTemplateExpression, is KtConstantExpression -> {
|
||||
return KtLightPsiLiteral(argument, lightParent)
|
||||
}
|
||||
is KtCallExpression -> {
|
||||
val arguments = argument.valueArguments
|
||||
val annotationName = argument.calleeExpression?.let { getAnnotationName(it) }
|
||||
if (annotationName != null) {
|
||||
return KtLightAnnotationForSourceEntry(
|
||||
annotationName,
|
||||
argument,
|
||||
lightParent,
|
||||
{ throw UnsupportedOperationException("cls delegate is not supported for nested annotations") })
|
||||
}
|
||||
val resolvedCall = argument.getResolvedCall()
|
||||
if (resolvedCall != null && CompileTimeConstantUtils.isArrayFunctionCall(resolvedCall))
|
||||
return KtLightPsiArrayInitializerMemberValue(
|
||||
argument,
|
||||
lightParent,
|
||||
{ self ->
|
||||
arguments.mapNotNull {
|
||||
it.getArgumentExpression()?.let { convertToLightAnnotationMemberValue(self, it) }
|
||||
}
|
||||
})
|
||||
}
|
||||
is KtCollectionLiteralExpression -> {
|
||||
val arguments = argument.getInnerExpressions()
|
||||
if (arguments.isNotEmpty())
|
||||
return KtLightPsiArrayInitializerMemberValue(
|
||||
argument,
|
||||
lightParent,
|
||||
{ self -> arguments.mapNotNull { convertToLightAnnotationMemberValue(self, it) } })
|
||||
}
|
||||
}
|
||||
// everything else (like complex constant references) considered as PsiLiteral-s
|
||||
return KtLightPsiLiteral(argument, lightParent)
|
||||
}
|
||||
|
||||
private val KtExpression.nameReference: KtNameReferenceExpression?
|
||||
get() = when {
|
||||
this is KtConstructorCalleeExpression -> constructorReferenceExpression as? KtNameReferenceExpression
|
||||
else -> this as? KtNameReferenceExpression
|
||||
}
|
||||
|
||||
private fun unwrapCall(callee: KtExpression): KtExpression = when (callee) {
|
||||
is KtDotQualifiedExpression -> callee.lastChild as? KtCallExpression ?: callee
|
||||
else -> callee
|
||||
}
|
||||
|
||||
private fun getAnnotationName(callee: KtExpression): String? {
|
||||
val callee = unwrapCall(callee)
|
||||
val resultingDescriptor = callee.getResolvedCall()?.resultingDescriptor
|
||||
if (resultingDescriptor is ClassConstructorDescriptor) {
|
||||
val ktClass = resultingDescriptor.constructedClass.source.getPsi() as? KtClass
|
||||
if (ktClass?.isAnnotation() == true) return ktClass.fqName?.toString()
|
||||
}
|
||||
if (resultingDescriptor is JavaClassConstructorDescriptor) {
|
||||
val psiClass = resultingDescriptor.constructedClass.source.getPsi() as? PsiClass
|
||||
if (psiClass?.isAnnotationType == true) return psiClass.qualifiedName
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
var accessAnnotationsClsDelegateIsAllowed = false
|
||||
|
||||
@TestOnly
|
||||
fun <T> withAllowedAnnotationsClsDelegate(body: () -> T): T {
|
||||
val prev = accessAnnotationsClsDelegateIsAllowed
|
||||
try {
|
||||
accessAnnotationsClsDelegateIsAllowed = true
|
||||
return body()
|
||||
} finally {
|
||||
accessAnnotationsClsDelegateIsAllowed = prev
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user