Remove 173 bunch files
This commit is contained in:
@@ -1,12 +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.cli.jvm.modules
|
||||
|
||||
import com.intellij.openapi.util.SystemInfo
|
||||
|
||||
fun isAtLeastJava9(): Boolean {
|
||||
return SystemInfo.isJavaVersionAtLeast("9")
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||
|
||||
description = "Kotlin Daemon Client"
|
||||
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
id("jps-compatible")
|
||||
}
|
||||
|
||||
jvmTarget = "1.6"
|
||||
|
||||
val nativePlatformVariants = listOf(
|
||||
"windows-amd64",
|
||||
"windows-i386",
|
||||
"osx-amd64",
|
||||
"osx-i386",
|
||||
"linux-amd64",
|
||||
"linux-i386",
|
||||
"freebsd-amd64-libcpp",
|
||||
"freebsd-amd64-libstdcpp",
|
||||
"freebsd-i386-libcpp",
|
||||
"freebsd-i386-libstdcpp"
|
||||
)
|
||||
|
||||
dependencies {
|
||||
compileOnly(project(":compiler:util"))
|
||||
compileOnly(project(":compiler:cli-common"))
|
||||
compileOnly(project(":compiler:daemon-common"))
|
||||
compileOnly(project(":kotlin-reflect-api"))
|
||||
compileOnly(project(":js:js.frontend"))
|
||||
compileOnly(commonDep("net.rubygrapefruit", "native-platform"))
|
||||
|
||||
embeddedComponents(project(":compiler:daemon-common")) { isTransitive = false }
|
||||
embeddedComponents(commonDep("net.rubygrapefruit", "native-platform"))
|
||||
nativePlatformVariants.forEach {
|
||||
embeddedComponents(commonDep("net.rubygrapefruit", "native-platform", "-$it"))
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
"main" { projectDefault() }
|
||||
"test" {}
|
||||
}
|
||||
|
||||
noDefaultJar()
|
||||
|
||||
runtimeJar(task<ShadowJar>("shadowJar")) {
|
||||
from(mainSourceSet.output)
|
||||
fromEmbeddedComponents()
|
||||
}
|
||||
|
||||
sourcesJar()
|
||||
|
||||
javadocJar()
|
||||
|
||||
dist()
|
||||
|
||||
ideaPlugin()
|
||||
|
||||
publish()
|
||||
-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
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
id("jps-compatible")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testCompile(project(":core:descriptors"))
|
||||
testCompile(project(":core:descriptors.jvm"))
|
||||
testCompile(project(":core:deserialization"))
|
||||
testCompile(project(":compiler:util"))
|
||||
testCompile(project(":compiler:backend"))
|
||||
testCompile(project(":compiler:fir:tree"))
|
||||
testCompile(project(":compiler:fir:psi2fir"))
|
||||
testCompile(project(":compiler:fir:cones"))
|
||||
testCompile(project(":compiler:fir:resolve"))
|
||||
testCompile(project(":compiler:fir:java"))
|
||||
testCompile(project(":compiler:ir.ir2cfg"))
|
||||
testCompile(project(":compiler:frontend"))
|
||||
testCompile(project(":compiler:frontend.java"))
|
||||
testCompile(project(":compiler:util"))
|
||||
testCompile(project(":compiler:cli-common"))
|
||||
testCompile(project(":compiler:cli"))
|
||||
testCompile(project(":compiler:light-classes"))
|
||||
testCompile(project(":compiler:serialization"))
|
||||
testCompile(project(":kotlin-preloader"))
|
||||
testCompile(project(":compiler:daemon-common"))
|
||||
testCompile(project(":js:js.serializer"))
|
||||
testCompile(project(":js:js.frontend"))
|
||||
testCompile(project(":js:js.translator"))
|
||||
testCompileOnly(project(":plugins:android-extensions-compiler"))
|
||||
testCompile(project(":kotlin-test:kotlin-test-jvm"))
|
||||
testCompile(projectTests(":compiler:tests-common-jvm6"))
|
||||
testCompileOnly(project(":kotlin-reflect-api"))
|
||||
testCompile(commonDep("junit:junit"))
|
||||
testCompile(androidDxJar()) { isTransitive = false }
|
||||
testCompileOnly(intellijCoreDep()) { includeJars("intellij-core") }
|
||||
testCompile(intellijDep()) {
|
||||
includeJars("openapi", "idea", "idea_rt", "guava", "trove4j", "picocontainer", "asm-all", "log4j", "jdom", "annotations", rootProject = rootProject)
|
||||
isTransitive = false
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
"main" { }
|
||||
"test" { projectDefault() }
|
||||
}
|
||||
|
||||
testsJar {}
|
||||
File diff suppressed because it is too large
Load Diff
-337
@@ -1,337 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-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.test.testFramework;
|
||||
|
||||
import com.intellij.core.CoreASTFactory;
|
||||
import com.intellij.lang.*;
|
||||
import com.intellij.lang.impl.PsiBuilderFactoryImpl;
|
||||
import com.intellij.mock.*;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.PathManager;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.EditorFactory;
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.fileEditor.impl.LoadTextUtil;
|
||||
import com.intellij.openapi.fileTypes.FileTypeFactory;
|
||||
import com.intellij.openapi.fileTypes.FileTypeManager;
|
||||
import com.intellij.openapi.progress.EmptyProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.progress.impl.CoreProgressManager;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.CharsetToolkit;
|
||||
import com.intellij.pom.PomModel;
|
||||
import com.intellij.pom.core.impl.PomModelImpl;
|
||||
import com.intellij.pom.tree.TreeAspect;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.*;
|
||||
import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry;
|
||||
import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistryImpl;
|
||||
import com.intellij.psi.impl.source.text.BlockSupportImpl;
|
||||
import com.intellij.psi.impl.source.text.DiffLog;
|
||||
import com.intellij.psi.util.CachedValuesManager;
|
||||
import com.intellij.testFramework.LightVirtualFile;
|
||||
import com.intellij.testFramework.TestDataFile;
|
||||
import com.intellij.util.CachedValuesManagerImpl;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.messages.MessageBus;
|
||||
import com.intellij.util.messages.MessageBusFactory;
|
||||
import junit.framework.TestCase;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.picocontainer.ComponentAdapter;
|
||||
import org.picocontainer.MutablePicoContainer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
|
||||
@SuppressWarnings("ALL")
|
||||
public abstract class KtParsingTestCase extends KtPlatformLiteFixture {
|
||||
public static final Key<Document> HARD_REF_TO_DOCUMENT_KEY = Key.create("HARD_REF_TO_DOCUMENT_KEY");
|
||||
protected String myFilePrefix = "";
|
||||
protected String myFileExt;
|
||||
protected final String myFullDataPath;
|
||||
protected PsiFile myFile;
|
||||
private MockPsiManager myPsiManager;
|
||||
private PsiFileFactoryImpl myFileFactory;
|
||||
protected Language myLanguage;
|
||||
private final ParserDefinition[] myDefinitions;
|
||||
private final boolean myLowercaseFirstLetter;
|
||||
|
||||
protected KtParsingTestCase(@NonNls @NotNull String dataPath, @NotNull String fileExt, @NotNull ParserDefinition... definitions) {
|
||||
this(dataPath, fileExt, false, definitions);
|
||||
}
|
||||
|
||||
protected KtParsingTestCase(@NonNls @NotNull String dataPath, @NotNull String fileExt, boolean lowercaseFirstLetter, @NotNull ParserDefinition... definitions) {
|
||||
myDefinitions = definitions;
|
||||
myFullDataPath = getTestDataPath() + "/" + dataPath;
|
||||
myFileExt = fileExt;
|
||||
myLowercaseFirstLetter = lowercaseFirstLetter;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
initApplication();
|
||||
ComponentAdapter component = getApplication().getPicoContainer().getComponentAdapter(ProgressManager.class.getName());
|
||||
|
||||
Extensions.registerAreaClass("IDEA_PROJECT", null);
|
||||
myProject = new MockProjectEx(getTestRootDisposable());
|
||||
myPsiManager = new MockPsiManager(myProject);
|
||||
myFileFactory = new PsiFileFactoryImpl(myPsiManager);
|
||||
MutablePicoContainer appContainer = getApplication().getPicoContainer();
|
||||
registerComponentInstance(appContainer, MessageBus.class, MessageBusFactory.newMessageBus(getApplication()));
|
||||
final MockEditorFactory editorFactory = new MockEditorFactory();
|
||||
registerComponentInstance(appContainer, EditorFactory.class, editorFactory);
|
||||
registerComponentInstance(appContainer, FileDocumentManager.class, new MockFileDocumentManagerImpl(new Function<CharSequence, Document>() {
|
||||
@Override
|
||||
public Document fun(CharSequence charSequence) {
|
||||
return editorFactory.createDocument(charSequence);
|
||||
}
|
||||
}, HARD_REF_TO_DOCUMENT_KEY));
|
||||
registerComponentInstance(appContainer, PsiDocumentManager.class, new MockPsiDocumentManager());
|
||||
registerApplicationService(PsiBuilderFactory.class, new PsiBuilderFactoryImpl());
|
||||
registerApplicationService(DefaultASTFactory.class, new CoreASTFactory());
|
||||
registerApplicationService(ReferenceProvidersRegistry.class, new ReferenceProvidersRegistryImpl());
|
||||
|
||||
registerApplicationService(ProgressManager.class, new CoreProgressManager());
|
||||
|
||||
myProject.registerService(CachedValuesManager.class, new CachedValuesManagerImpl(myProject, new PsiCachedValuesFactory(myPsiManager)));
|
||||
myProject.registerService(PsiManager.class, myPsiManager);
|
||||
|
||||
this.registerExtensionPoint(FileTypeFactory.FILE_TYPE_FACTORY_EP, FileTypeFactory.class);
|
||||
registerExtensionPoint(MetaLanguage.EP_NAME, MetaLanguage.class);
|
||||
|
||||
for (ParserDefinition definition : myDefinitions) {
|
||||
addExplicitExtension(LanguageParserDefinitions.INSTANCE, definition.getFileNodeType().getLanguage(), definition);
|
||||
}
|
||||
if (myDefinitions.length > 0) {
|
||||
configureFromParserDefinition(myDefinitions[0], myFileExt);
|
||||
}
|
||||
|
||||
// That's for reparse routines
|
||||
final PomModelImpl pomModel = new PomModelImpl(myProject);
|
||||
myProject.registerService(PomModel.class, pomModel);
|
||||
new TreeAspect(pomModel);
|
||||
}
|
||||
|
||||
public void configureFromParserDefinition(ParserDefinition definition, String extension) {
|
||||
myLanguage = definition.getFileNodeType().getLanguage();
|
||||
myFileExt = extension;
|
||||
addExplicitExtension(LanguageParserDefinitions.INSTANCE, this.myLanguage, definition);
|
||||
registerComponentInstance(
|
||||
getApplication().getPicoContainer(), FileTypeManager.class,
|
||||
new MockFileTypeManager(new MockLanguageFileType(myLanguage, myFileExt)));
|
||||
}
|
||||
|
||||
protected <T> void addExplicitExtension(final LanguageExtension<T> instance, final Language language, final T object) {
|
||||
instance.addExplicitExtension(language, object);
|
||||
Disposer.register(myProject, new Disposable() {
|
||||
@Override
|
||||
public void dispose() {
|
||||
instance.removeExplicitExtension(language, object);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <T> void registerExtensionPoint(final ExtensionPointName<T> extensionPointName, Class<T> aClass) {
|
||||
super.registerExtensionPoint(extensionPointName, aClass);
|
||||
Disposer.register(myProject, new Disposable() {
|
||||
@Override
|
||||
public void dispose() {
|
||||
Extensions.getRootArea().unregisterExtensionPoint(extensionPointName.getName());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected <T> void registerApplicationService(final Class<T> aClass, T object) {
|
||||
getApplication().registerService(aClass, object);
|
||||
Disposer.register(myProject, new Disposable() {
|
||||
@Override
|
||||
public void dispose() {
|
||||
getApplication().getPicoContainer().unregisterComponent(aClass.getName());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public MockProjectEx getProject() {
|
||||
return myProject;
|
||||
}
|
||||
|
||||
public MockPsiManager getPsiManager() {
|
||||
return myPsiManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
myFile = null;
|
||||
myProject = null;
|
||||
myPsiManager = null;
|
||||
}
|
||||
|
||||
protected String getTestDataPath() {
|
||||
return PathManager.getHomePath();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public final String getTestName() {
|
||||
return getTestName(myLowercaseFirstLetter);
|
||||
}
|
||||
|
||||
protected boolean includeRanges() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean skipSpaces() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean checkAllPsiRoots() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void doTest(boolean checkResult) {
|
||||
String name = getTestName();
|
||||
try {
|
||||
String text = loadFile(name + "." + myFileExt);
|
||||
myFile = createPsiFile(name, text);
|
||||
ensureParsed(myFile);
|
||||
assertEquals("light virtual file text mismatch", text, ((LightVirtualFile)myFile.getVirtualFile()).getContent().toString());
|
||||
assertEquals("virtual file text mismatch", text, LoadTextUtil.loadText(myFile.getVirtualFile()));
|
||||
assertEquals("doc text mismatch", text, myFile.getViewProvider().getDocument().getText());
|
||||
assertEquals("psi text mismatch", text, myFile.getText());
|
||||
ensureCorrectReparse(myFile);
|
||||
if (checkResult){
|
||||
checkResult(name, myFile);
|
||||
}
|
||||
else{
|
||||
toParseTreeText(myFile, skipSpaces(), includeRanges());
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected void doTest(String suffix) throws IOException {
|
||||
String name = getTestName();
|
||||
String text = loadFile(name + "." + myFileExt);
|
||||
myFile = createPsiFile(name, text);
|
||||
ensureParsed(myFile);
|
||||
assertEquals(text, myFile.getText());
|
||||
checkResult(name + suffix, myFile);
|
||||
}
|
||||
|
||||
protected void doCodeTest(String code) throws IOException {
|
||||
String name = getTestName();
|
||||
myFile = createPsiFile("a", code);
|
||||
ensureParsed(myFile);
|
||||
assertEquals(code, myFile.getText());
|
||||
checkResult(myFilePrefix + name, myFile);
|
||||
}
|
||||
|
||||
protected PsiFile createPsiFile(String name, String text) {
|
||||
return createFile(name + "." + myFileExt, text);
|
||||
}
|
||||
|
||||
protected PsiFile createFile(@NonNls String name, String text) {
|
||||
LightVirtualFile virtualFile = new LightVirtualFile(name, myLanguage, text);
|
||||
virtualFile.setCharset(CharsetToolkit.UTF8_CHARSET);
|
||||
return createFile(virtualFile);
|
||||
}
|
||||
|
||||
protected PsiFile createFile(LightVirtualFile virtualFile) {
|
||||
return myFileFactory.trySetupPsiForFile(virtualFile, myLanguage, true, false);
|
||||
}
|
||||
|
||||
protected void checkResult(@NonNls @TestDataFile String targetDataName, final PsiFile file) throws IOException {
|
||||
doCheckResult(myFullDataPath, file, checkAllPsiRoots(), targetDataName, skipSpaces(), includeRanges());
|
||||
}
|
||||
|
||||
public static void doCheckResult(String testDataDir,
|
||||
PsiFile file,
|
||||
boolean checkAllPsiRoots,
|
||||
String targetDataName,
|
||||
boolean skipSpaces,
|
||||
boolean printRanges) throws IOException {
|
||||
FileViewProvider provider = file.getViewProvider();
|
||||
Set<Language> languages = provider.getLanguages();
|
||||
|
||||
if (!checkAllPsiRoots || languages.size() == 1) {
|
||||
doCheckResult(testDataDir, targetDataName + ".txt", toParseTreeText(file, skipSpaces, printRanges).trim());
|
||||
return;
|
||||
}
|
||||
|
||||
for (Language language : languages) {
|
||||
PsiFile root = provider.getPsi(language);
|
||||
String expectedName = targetDataName + "." + language.getID() + ".txt";
|
||||
doCheckResult(testDataDir, expectedName, toParseTreeText(root, skipSpaces, printRanges).trim());
|
||||
}
|
||||
}
|
||||
|
||||
protected void checkResult(String actual) throws IOException {
|
||||
String name = getTestName();
|
||||
doCheckResult(myFullDataPath, myFilePrefix + name + ".txt", actual);
|
||||
}
|
||||
|
||||
protected void checkResult(@TestDataFile @NonNls String targetDataName, String actual) throws IOException {
|
||||
doCheckResult(myFullDataPath, targetDataName, actual);
|
||||
}
|
||||
|
||||
public static void doCheckResult(String fullPath, String targetDataName, String actual) throws IOException {
|
||||
String expectedFileName = fullPath + File.separatorChar + targetDataName;
|
||||
KtUsefulTestCase.assertSameLinesWithFile(expectedFileName, actual);
|
||||
}
|
||||
|
||||
protected static String toParseTreeText(PsiElement file, boolean skipSpaces, boolean printRanges) {
|
||||
return DebugUtil.psiToString(file, skipSpaces, printRanges);
|
||||
}
|
||||
|
||||
protected String loadFile(@NonNls @TestDataFile String name) throws IOException {
|
||||
return loadFileDefault(myFullDataPath, name);
|
||||
}
|
||||
|
||||
public static String loadFileDefault(String dir, String name) throws IOException {
|
||||
return FileUtil.loadFile(new File(dir, name), CharsetToolkit.UTF8, true).trim();
|
||||
}
|
||||
|
||||
public static void ensureParsed(PsiFile file) {
|
||||
file.accept(new PsiElementVisitor() {
|
||||
@Override
|
||||
public void visitElement(PsiElement element) {
|
||||
element.acceptChildren(this);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void ensureCorrectReparse(@NotNull PsiFile file) {
|
||||
String psiToStringDefault = DebugUtil.psiToString(file, false, false);
|
||||
String fileText = file.getText();
|
||||
DiffLog diffLog = (new BlockSupportImpl(file.getProject())).reparseRange(
|
||||
file, file.getNode(), TextRange.allOf(fileText), fileText, new EmptyProgressIndicator(), fileText);
|
||||
diffLog.performActualPsiChange(file);
|
||||
|
||||
TestCase.assertEquals(psiToStringDefault, DebugUtil.psiToString(file, false, false));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user