Uast: Move all IDE-related code to uast-idea, get rid of the 'idea' dependency

Uast is used in the CLI version of Android Lint so 'uast-kotlin' should run correctly even without IDE.
This commit is contained in:
Yan Zhulanow
2018-06-16 00:06:24 +03:00
parent 8d9c53da92
commit 06af2a88f0
10 changed files with 92 additions and 51 deletions
+2 -2
View File
@@ -129,8 +129,8 @@
displayName="Incompatible API usage"
implementationClass="org.jetbrains.kotlin.idea.inspections.api.IncompatibleAPIInspection"/>
<projectService serviceInterface="org.jetbrains.uast.kotlin.KotlinUastBindingContextProviderService"
serviceImplementation="org.jetbrains.uast.kotlin.internal.IdeaKotlinUastBindingContextProviderService"/>
<projectService serviceInterface="org.jetbrains.uast.kotlin.KotlinUastResolveProviderService"
serviceImplementation="org.jetbrains.uast.kotlin.internal.IdeaKotlinUastResolveProviderService"/>
</extensions>
<extensions defaultExtensionNs="org.jetbrains.uast">
@@ -10,6 +10,7 @@ dependencies {
compile(project(":compiler:backend"))
compile(project(":compiler:frontend.java"))
compile(project(":idea:ide-common"))
compile(project(":idea:idea-core"))
compile(project(":plugins:uast-kotlin"))
compileOnly(intellijDep())
}
@@ -16,16 +16,22 @@
package org.jetbrains.uast.kotlin.internal
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.codegen.ClassBuilderMode
import org.jetbrains.kotlin.codegen.state.IncompatibleClassTracker
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.uast.kotlin.KotlinUastBindingContextProviderService
import org.jetbrains.uast.kotlin.KotlinUastResolveProviderService
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
import org.jetbrains.kotlin.idea.project.languageVersionSettings
import org.jetbrains.kotlin.idea.util.module
class IdeaKotlinUastBindingContextProviderService : KotlinUastBindingContextProviderService {
class IdeaKotlinUastResolveProviderService : KotlinUastResolveProviderService {
override fun getBindingContext(element: KtElement) = element.analyze(BodyResolveMode.PARTIAL)
override fun getTypeMapper(element: KtElement): KotlinTypeMapper? {
@@ -34,4 +40,13 @@ class IdeaKotlinUastBindingContextProviderService : KotlinUastBindingContextProv
IncompatibleClassTracker.DoNothing, JvmAbi.DEFAULT_MODULE_NAME, false, KotlinTypeMapper.RELEASE_COROUTINES_DEFAULT
)
}
override fun isJvmElement(psiElement: PsiElement): Boolean {
val module = psiElement.module
return module == null || TargetPlatformDetector.getPlatform(module) is JvmPlatform
}
override fun getLanguageVersionSettings(element: KtElement): LanguageVersionSettings {
return element.languageVersionSettings
}
}
+5 -3
View File
@@ -11,8 +11,10 @@ dependencies {
compile(project(":compiler:frontend"))
compile(project(":compiler:frontend.java"))
compile(project(":compiler:light-classes"))
compile(project(":idea:idea-core"))
compileOnly(intellijDep()) { includeJars("openapi", "idea", "java-api", "java-impl", "platform-api", "platform-impl", "util", "extensions", "asm-all") }
// BEWARE: Uast should not depend on IDEA.
compileOnly(intellijCoreDep()) { includeJars("intellij-core") }
compileOnly(intellijDep()) { includeJars("java-api", "java-impl", "asm-all") }
testCompile(projectDist(":kotlin-test:kotlin-test-jvm"))
testCompile(projectTests(":compiler:tests-common"))
@@ -20,7 +22,7 @@ dependencies {
testCompile(project(":compiler:util"))
testCompile(project(":compiler:cli"))
testCompile(projectTests(":idea:idea-test-framework"))
testCompileOnly(intellijDep()) { includeJars("java-api", "java-impl", "idea_rt") }
testCompileOnly(intellijDep()) { includeJars("java-api", "java-impl") }
testRuntime(projectDist(":kotlin-reflect"))
testRuntime(project(":idea:idea-android"))
@@ -17,6 +17,7 @@
package org.jetbrains.uast.kotlin
import com.intellij.lang.Language
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.util.Key
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
@@ -27,19 +28,17 @@ import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
import org.jetbrains.kotlin.asJava.elements.*
import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
import org.jetbrains.kotlin.idea.util.module
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
import org.jetbrains.uast.*
import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier
import org.jetbrains.uast.kotlin.declarations.KotlinUMethod
@@ -47,9 +46,11 @@ import org.jetbrains.uast.kotlin.expressions.*
import org.jetbrains.uast.kotlin.psi.UastKotlinPsiParameter
import org.jetbrains.uast.kotlin.psi.UastKotlinPsiVariable
interface KotlinUastBindingContextProviderService {
interface KotlinUastResolveProviderService {
fun getBindingContext(element: KtElement): BindingContext
fun getTypeMapper(element: KtElement): KotlinTypeMapper?
fun getLanguageVersionSettings(element: KtElement): LanguageVersionSettings
fun isJvmElement(psiElement: PsiElement): Boolean
}
var PsiElement.destructuringDeclarationInitializer: Boolean? by UserDataProperty(Key.create("kotlin.uast.destructuringDeclarationInitializer"))
@@ -64,14 +65,10 @@ class KotlinUastLanguagePlugin : UastLanguagePlugin {
return fileName.endsWith(".kt", false) || fileName.endsWith(".kts", false)
}
private val PsiElement.isJvmElement
get() = try {
// Workaround for UAST used without full-fledged IDEA when ProjectFileIndex is not available
// If we can't get the module (or don't have one), act as if the current platform is JVM
val module = module
module == null || TargetPlatformDetector.getPlatform(module) is JvmPlatform
} catch (e: Exception) {
true
private val PsiElement.isJvmElement: Boolean
get() {
val resolveProvider = ServiceManager.getService(project, KotlinUastResolveProviderService::class.java)
return resolveProvider.isJvmElement(this)
}
override fun convertElement(element: PsiElement, parent: UElement?, requiredType: Class<out UElement>?): UElement? {
@@ -17,6 +17,7 @@
package org.jetbrains.uast.kotlin
import com.intellij.lang.Language
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.util.Key
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
@@ -27,11 +28,10 @@ import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
import org.jetbrains.kotlin.asJava.elements.*
import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
import org.jetbrains.kotlin.idea.util.module
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
@@ -45,9 +45,11 @@ import org.jetbrains.uast.kotlin.expressions.*
import org.jetbrains.uast.kotlin.psi.UastKotlinPsiParameter
import org.jetbrains.uast.kotlin.psi.UastKotlinPsiVariable
interface KotlinUastBindingContextProviderService {
interface KotlinUastResolveProviderService {
fun getBindingContext(element: KtElement): BindingContext
fun getTypeMapper(element: KtElement): KotlinTypeMapper?
fun getLanguageVersionSettings(element: KtElement): LanguageVersionSettings
fun isJvmElement(psiElement: PsiElement): Boolean
}
var PsiElement.destructuringDeclarationInitializer: Boolean? by UserDataProperty(Key.create("kotlin.uast.destructuringDeclarationInitializer"))
@@ -64,14 +66,10 @@ class KotlinUastLanguagePlugin : UastLanguagePlugin {
return fileName.endsWith(".kt", false) || fileName.endsWith(".kts", false)
}
private val PsiElement.isJvmElement
get() = try {
// Workaround for UAST used without full-fledged IDEA when ProjectFileIndex is not available
// If we can't get the module (or don't have one), act as if the current platform is JVM
val module = module
module == null || TargetPlatformDetector.getPlatform(module) is JvmPlatform
} catch (e: Exception) {
true
private val PsiElement.isJvmElement: Boolean
get() {
val resolveProvider = ServiceManager.getService(project, KotlinUastResolveProviderService::class.java)
return resolveProvider.isJvmElement(this)
}
override fun convertElement(element: PsiElement, parent: UElement?, requiredType: Class<out UElement>?): UElement? {
@@ -17,6 +17,7 @@
package org.jetbrains.uast.kotlin
import com.intellij.lang.Language
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.util.Key
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
@@ -27,13 +28,12 @@ import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
import org.jetbrains.kotlin.asJava.elements.*
import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
import org.jetbrains.kotlin.idea.util.module
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
@@ -46,9 +46,11 @@ import org.jetbrains.uast.kotlin.expressions.*
import org.jetbrains.uast.kotlin.psi.UastKotlinPsiParameter
import org.jetbrains.uast.kotlin.psi.UastKotlinPsiVariable
interface KotlinUastBindingContextProviderService {
interface KotlinUastResolveProviderService {
fun getBindingContext(element: KtElement): BindingContext
fun getTypeMapper(element: KtElement): KotlinTypeMapper?
fun getLanguageVersionSettings(element: KtElement): LanguageVersionSettings
fun isJvmElement(psiElement: PsiElement): Boolean
}
var PsiElement.destructuringDeclarationInitializer: Boolean? by UserDataProperty(Key.create("kotlin.uast.destructuringDeclarationInitializer"))
@@ -63,14 +65,10 @@ class KotlinUastLanguagePlugin : UastLanguagePlugin {
return fileName.endsWith(".kt", false) || fileName.endsWith(".kts", false)
}
private val PsiElement.isJvmElement
get() = try {
// Workaround for UAST used without full-fledged IDEA when ProjectFileIndex is not available
// If we can't get the module (or don't have one), act as if the current platform is JVM
val module = module
module == null || TargetPlatformDetector.getPlatform(module) is JvmPlatform
} catch (e: Exception) {
true
private val PsiElement.isJvmElement: Boolean
get() {
val resolveProvider = ServiceManager.getService(project, KotlinUastResolveProviderService::class.java)
return resolveProvider.isJvmElement(this)
}
override fun convertElement(element: PsiElement, parent: UElement?, requiredType: Class<out UElement>?): UElement? {
@@ -1,10 +1,16 @@
package org.jetbrains.uast.kotlin.internal
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.analyzer.AnalysisResult
import org.jetbrains.kotlin.codegen.ClassBuilderMode
import org.jetbrains.kotlin.codegen.state.IncompatibleClassTracker
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
import org.jetbrains.kotlin.container.ComponentProvider
import org.jetbrains.kotlin.container.get
import org.jetbrains.kotlin.context.ProjectContext
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.psi.KtElement
@@ -12,9 +18,9 @@ import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension
import org.jetbrains.uast.kotlin.KotlinUastBindingContextProviderService
import org.jetbrains.uast.kotlin.KotlinUastResolveProviderService
class CliKotlinUastBindingContextProviderService : KotlinUastBindingContextProviderService {
class CliKotlinUastResolveProviderService : KotlinUastResolveProviderService {
val Project.analysisCompletedHandler: UastAnalysisHandlerExtension?
get() = getExtensions(AnalysisHandlerExtension.extensionPointName)
.filterIsInstance<UastAnalysisHandlerExtension>()
@@ -27,14 +33,23 @@ class CliKotlinUastBindingContextProviderService : KotlinUastBindingContextProvi
override fun getTypeMapper(element: KtElement): KotlinTypeMapper? {
return element.project.analysisCompletedHandler?.getTypeMapper()
}
override fun isJvmElement(psiElement: PsiElement) = true
override fun getLanguageVersionSettings(element: KtElement): LanguageVersionSettings {
return element.project.analysisCompletedHandler?.getLanguageVersionSettings() ?: LanguageVersionSettingsImpl.DEFAULT
}
}
class UastAnalysisHandlerExtension : AnalysisHandlerExtension {
private var context: BindingContext? = null
private var typeMapper: KotlinTypeMapper? = null
private var languageVersionSettings: LanguageVersionSettings? = null
fun getBindingContext() = context
fun getLanguageVersionSettings() = languageVersionSettings
fun getTypeMapper(): KotlinTypeMapper? {
if (typeMapper != null) return typeMapper
val bindingContext = context ?: return null
@@ -47,6 +62,18 @@ class UastAnalysisHandlerExtension : AnalysisHandlerExtension {
return typeMapper
}
override fun doAnalysis(
project: Project,
module: ModuleDescriptor,
projectContext: ProjectContext,
files: Collection<KtFile>,
bindingTrace: BindingTrace,
componentProvider: ComponentProvider
): AnalysisResult? {
languageVersionSettings = componentProvider.get<LanguageVersionSettings>()
return super.doAnalysis(project, module, projectContext, files, bindingTrace, componentProvider)
}
override fun analysisCompleted(
project: Project,
module: ModuleDescriptor,
@@ -33,7 +33,6 @@ import org.jetbrains.kotlin.asJava.toLightElements
import org.jetbrains.kotlin.builtins.isBuiltinFunctionalTypeOrSubtype
import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.project.languageVersionSettings
import org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaPackageFragment
import org.jetbrains.kotlin.load.java.sam.SamConstructorDescriptor
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryPackageSourceElement
@@ -202,12 +201,16 @@ internal fun KotlinType.toPsiType(lightDeclaration: PsiModifierListOwner?, conte
if (this.containsLocalTypes()) return UastErrorType
val project = context.project
val typeMapper = ServiceManager.getService(project, KotlinUastBindingContextProviderService::class.java)
val typeMapper = ServiceManager.getService(project, KotlinUastResolveProviderService::class.java)
.getTypeMapper(context) ?: return UastErrorType
val languageVersionSettings = ServiceManager.getService(project, KotlinUastResolveProviderService::class.java)
.getLanguageVersionSettings(context)
val signatureWriter = BothSignatureWriter(BothSignatureWriter.Mode.TYPE)
val typeMappingMode = if (boxed) TypeMappingMode.GENERIC_ARGUMENT else TypeMappingMode.DEFAULT
val approximatedType = TypeApproximator().approximateDeclarationType(this, true, context.languageVersionSettings)
val approximatedType = TypeApproximator().approximateDeclarationType(this, true, languageVersionSettings)
typeMapper.mapType(approximatedType, signatureWriter, typeMappingMode)
val signature = StringCharacterIterator(signatureWriter.toString())
@@ -281,7 +284,7 @@ internal fun KtExpression.unwrapBlockOrParenthesis(): KtExpression {
internal fun KtElement.analyze(): BindingContext {
if (containingFile !is KtFile) return BindingContext.EMPTY // EA-114080, EA-113475
return ServiceManager.getService(project, KotlinUastBindingContextProviderService::class.java)
return ServiceManager.getService(project, KotlinUastResolveProviderService::class.java)
?.getBindingContext(this) ?: BindingContext.EMPTY
}
@@ -25,10 +25,10 @@ import org.jetbrains.kotlin.test.TestJdkKind
import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase
import org.jetbrains.uast.UastLanguagePlugin
import org.jetbrains.uast.evaluation.UEvaluatorExtension
import org.jetbrains.uast.kotlin.KotlinUastBindingContextProviderService
import org.jetbrains.uast.kotlin.KotlinUastResolveProviderService
import org.jetbrains.uast.kotlin.KotlinUastLanguagePlugin
import org.jetbrains.uast.kotlin.evaluation.KotlinEvaluatorExtension
import org.jetbrains.uast.kotlin.internal.CliKotlinUastBindingContextProviderService
import org.jetbrains.uast.kotlin.internal.CliKotlinUastResolveProviderService
import org.jetbrains.uast.kotlin.internal.UastAnalysisHandlerExtension
import org.jetbrains.uast.test.env.AbstractCoreEnvironment
import org.jetbrains.uast.test.env.AbstractUastTest
@@ -72,8 +72,8 @@ abstract class AbstractKotlinUastTest : AbstractUastTest() {
.registerExtension(KotlinEvaluatorExtension())
project.registerService(
KotlinUastBindingContextProviderService::class.java,
CliKotlinUastBindingContextProviderService::class.java)
KotlinUastResolveProviderService::class.java,
CliKotlinUastResolveProviderService::class.java)
}
override fun createEnvironment(source: File): AbstractCoreEnvironment {