FIR IDE: Move fir resolving functionality from idea module to idea-frontend-fir

This commit is contained in:
Ilya Kirillov
2020-05-24 15:01:37 +03:00
parent 003827a4f2
commit 45ef0e1b50
26 changed files with 181 additions and 41 deletions
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2016 JetBrains s.r.o. * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
* 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.idea.highlighter package org.jetbrains.kotlin.idea.highlighter
@@ -59,6 +48,7 @@ open class KotlinPsiChecker : Annotator, HighlightRangeExtension {
if (!KotlinHighlightingUtil.shouldHighlight(file)) return if (!KotlinHighlightingUtil.shouldHighlight(file)) return
//todo move all fir stuff to fir plugin
if (FirResolution.enabled) { if (FirResolution.enabled) {
annotateElementUsingFrontendIR(element, file, holder) annotateElementUsingFrontendIR(element, file, holder)
} else { } else {
@@ -24,9 +24,6 @@ import org.jetbrains.kotlin.fir.types.ConeLookupTagBasedType
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.fir.FirResolution
import org.jetbrains.kotlin.idea.fir.firResolveState
import org.jetbrains.kotlin.idea.fir.getOrBuildFir
import org.jetbrains.kotlin.idea.util.application.runWithCancellationCheck import org.jetbrains.kotlin.idea.util.application.runWithCancellationCheck
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
@@ -66,10 +63,6 @@ object KotlinDescriptorsBasedReferenceResolver : ResolveCache.PolyVariantResolve
class KotlinResolveResult(element: PsiElement) : PsiElementResolveResult(element) class KotlinResolveResult(element: PsiElement) : PsiElementResolveResult(element)
private fun resolveToPsiElements(ref: KtDescriptorsBasedReference): Collection<PsiElement> { private fun resolveToPsiElements(ref: KtDescriptorsBasedReference): Collection<PsiElement> {
if (FirResolution.enabled) {
@Suppress("UNCHECKED_CAST")
return FirReferenceResolveHelper.resolveToPsiElements(ref as AbstractKtReference<KtElement>)
}
val bindingContext = ref.element.analyze(BodyResolveMode.PARTIAL) val bindingContext = ref.element.analyze(BodyResolveMode.PARTIAL)
return resolveToPsiElements(ref, bindingContext, ref.getTargetDescriptors(bindingContext)) return resolveToPsiElements(ref, bindingContext, ref.getTargetDescriptors(bindingContext))
} }
@@ -45,6 +45,9 @@ class KtSimpleNameReferenceDescriptorsImpl(
override fun doCanBeReferenceTo(candidateTarget: PsiElement): Boolean = override fun doCanBeReferenceTo(candidateTarget: PsiElement): Boolean =
canBeReferenceTo(candidateTarget) canBeReferenceTo(candidateTarget)
override fun isReferenceToWithoutExtensionChecking(candidateTarget: PsiElement): Boolean =
matchesTarget(candidateTarget)
override fun getTargetDescriptors(context: BindingContext): Collection<DeclarationDescriptor> { override fun getTargetDescriptors(context: BindingContext): Collection<DeclarationDescriptor> {
return SmartList<DeclarationDescriptor>().apply { return SmartList<DeclarationDescriptor>().apply {
// Replace Java property with its accessor(s) // Replace Java property with its accessor(s)
+3 -1
View File
@@ -4,6 +4,8 @@ plugins {
} }
dependencies { dependencies {
compile(project(":idea:idea-frontend-fir"))
testCompileOnly(toolsJar()) testCompileOnly(toolsJar())
testRuntimeOnly(toolsJar()) testRuntimeOnly(toolsJar())
@@ -54,7 +56,7 @@ sourceSets {
"test" { projectDefault() } "test" { projectDefault() }
} }
projectTest(parallel = true) { projectTest(parallel = false) {
dependsOn(":dist") dependsOn(":dist")
workingDir = rootDir workingDir = rootDir
} }
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.idea.fir
import com.intellij.openapi.components.ServiceManager import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.util.ModificationTracker import com.intellij.openapi.util.ModificationTracker
import org.jetbrains.kotlin.analyzer.KotlinModificationTrackerService
import org.jetbrains.kotlin.analyzer.TrackableModuleInfo import org.jetbrains.kotlin.analyzer.TrackableModuleInfo
import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
@@ -60,5 +59,5 @@ class FirIdeResolveStateServiceImpl(val project: Project) : FirIdeResolveStateSe
} }
override val fallbackModificationTracker: ModificationTracker? = override val fallbackModificationTracker: ModificationTracker? =
KotlinModificationTrackerService.getInstance(project).outOfBlockModificationTracker org.jetbrains.kotlin.analyzer.KotlinModificationTrackerService.getInstance(project).outOfBlockModificationTracker
} }
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@@ -1,6 +1,6 @@
/* /*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* that can be found in the license/LICENSE.txt file. * 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.idea.fir package org.jetbrains.kotlin.idea.fir
@@ -0,0 +1,12 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.idea.references
import com.intellij.psi.impl.source.resolve.ResolveCache
interface FirKtReference : KtReference {
override val resolver get() = KtFirReferenceResolver
}
@@ -65,7 +65,7 @@ object FirReferenceResolveHelper {
} }
} }
fun resolveToPsiElements(ref: AbstractKtReference<KtElement>): Collection<PsiElement> { fun resolveToPsiElements(ref: AbstractKtReference<*>): Collection<PsiElement> {
val expression = ref.expression val expression = ref.expression
val state = expression.firResolveState() val state = expression.firResolveState()
val session = state.getSession(expression) val session = state.getSession(expression)
@@ -0,0 +1,42 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.idea.references
import com.intellij.psi.PsiElement
import com.intellij.psi.impl.source.resolve.ResolveCache
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtImportAlias
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
internal class KtSimpleNameReferenceFirImpl(
expression: KtSimpleNameExpression
) : KtSimpleNameReference(expression), FirKtReference {
override fun doCanBeReferenceTo(candidateTarget: PsiElement): Boolean {
return true // TODO
}
override fun isReferenceToWithoutExtensionChecking(candidateTarget: PsiElement): Boolean {
return resolve() == candidateTarget
}
override fun handleElementRename(newElementName: String): PsiElement? {
TODO("Not yet implemented")
}
override fun bindToElement(element: PsiElement, shorteningMode: ShorteningMode): PsiElement {
TODO("Not yet implemented")
}
override fun bindToFqName(fqName: FqName, shorteningMode: ShorteningMode, targetElement: PsiElement?): PsiElement {
TODO("Not yet implemented")
}
override fun getImportAlias(): KtImportAlias? {
TODO("Not yet implemented")
}
override val resolver get() = KtFirReferenceResolver
}
@@ -0,0 +1,14 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.idea.references
class KotlinFirReferenceContributor : KotlinReferenceProviderContributor {
override fun registerReferenceProviders(registrar: KotlinPsiReferenceRegistrar) {
with(registrar) {
registerProvider(factory = ::KtSimpleNameReferenceFirImpl)
}
}
}
@@ -0,0 +1,21 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.idea.references
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiElementResolveResult
import com.intellij.psi.ResolveResult
import com.intellij.psi.impl.source.resolve.ResolveCache
object KtFirReferenceResolver : ResolveCache.PolyVariantResolver<KtReference> {
class KotlinResolveResult(element: PsiElement) : PsiElementResolveResult(element)
override fun resolve(ref: KtReference, incompleteCode: Boolean): Array<ResolveResult> {
check(ref is AbstractKtReference<*>) { "reference should be AbstractKtReference, but was ${ref::class}" }
val resolveToPsiElements = FirReferenceResolveHelper.resolveToPsiElements(ref)
return resolveToPsiElements.map { KotlinResolveResult(it) }.toTypedArray()
}
}
@@ -5,11 +5,14 @@ plugins {
dependencies { dependencies {
/* /*
This module should not depend on compiler scpecific functionality This module should not depend on compiler specific functionality
No dependencies on descriptors (for now we still have transitive one by psi module), fir and similar modules, No dependencies on descriptors (for now we still have transitive one by psi module), fir and similar modules,
but may be dependencies on frontend independent one like psi & type-system but may be dependencies on frontend independent one like psi & type-system
This module is needed for smooth migration from descriptor frontend based IJ plugin to interlayer based one This module is needed for smooth migration from descriptor frontend based IJ plugin to interlayer based one
*/ */
compileOnly(project(":compiler:frontend")) // we need caches form here to work with ModuleInfo :(
compileOnly(project(":compiler:psi")) compileOnly(project(":compiler:psi"))
compileOnly(project(":kotlin-reflect-api")) compileOnly(project(":kotlin-reflect-api"))
compileOnly(intellijCoreDep()) compileOnly(intellijCoreDep())
@@ -0,0 +1,62 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.caches.project
import com.intellij.openapi.module.Module
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ProjectRootModificationTracker
import com.intellij.openapi.util.UserDataHolder
import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.CachedValuesManager
fun <T> Module.cacheByClass(classForKey: Class<*>, vararg dependencies: Any, provider: () -> T): T {
return CachedValuesManager.getManager(project).cache(this, dependencies, classForKey, provider)
}
fun <T> Module.cacheByClassInvalidatingOnRootModifications(classForKey: Class<*>, provider: () -> T): T {
return cacheByClass(classForKey, ProjectRootModificationTracker.getInstance(project), provider = provider)
}
/**
* Note that it uses lambda's class for caching (essentially, anonymous class), which means that all invocations will be cached
* by the one and the same key.
* It is encouraged to use explicit class, just for the sake of readability.
*/
fun <T> Module.cacheInvalidatingOnRootModifications(provider: () -> T): T {
return cacheByClassInvalidatingOnRootModifications(provider::class.java, provider)
}
fun <T> Project.cacheByClass(classForKey: Class<*>, vararg dependencies: Any, provider: () -> T): T {
return CachedValuesManager.getManager(this).cache(this, dependencies, classForKey, provider)
}
fun <T> Project.cacheByClassInvalidatingOnRootModifications(classForKey: Class<*>, provider: () -> T): T {
return cacheByClass(classForKey, ProjectRootModificationTracker.getInstance(this), provider = provider)
}
/**
* Note that it uses lambda's class for caching (essentially, anonymous class), which means that all invocations will be cached
* by the one and the same key.
* It is encouraged to use explicit class, just for the sake of readability.
*/
fun <T> Project.cacheInvalidatingOnRootModifications(provider: () -> T): T {
return cacheByClassInvalidatingOnRootModifications(provider::class.java, provider)
}
private fun <T> CachedValuesManager.cache(
holder: UserDataHolder,
dependencies: Array<out Any>,
classForKey: Class<*>,
provider: () -> T
): T {
return getCachedValue(
holder,
getKeyForClass(classForKey),
{ CachedValueProvider.Result.create(provider(), dependencies) },
false
)
}
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@@ -11,9 +11,7 @@ import com.intellij.psi.util.PsiModificationTracker
import org.jetbrains.kotlin.analyzer.KotlinModificationTrackerService import org.jetbrains.kotlin.analyzer.KotlinModificationTrackerService
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
class KotlinIDEModificationTrackerService(project: Project) : class KotlinIDEModificationTrackerService(project: Project) : KotlinModificationTrackerService() {
KotlinModificationTrackerService() {
override val modificationTracker: ModificationTracker = PsiModificationTracker.SERVICE.getInstance(project) override val modificationTracker: ModificationTracker = PsiModificationTracker.SERVICE.getInstance(project)
override val outOfBlockModificationTracker: ModificationTracker = override val outOfBlockModificationTracker: ModificationTracker =
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@@ -28,10 +28,11 @@ abstract class KtSimpleNameReference(expression: KtSimpleNameExpression) : KtSim
if (extension.isReferenceTo(this, element)) return true if (extension.isReferenceTo(this, element)) return true
} }
return super.isReferenceTo(element) return isReferenceToWithoutExtensionChecking(element)
} }
protected abstract fun doCanBeReferenceTo(candidateTarget: PsiElement): Boolean protected abstract fun doCanBeReferenceTo(candidateTarget: PsiElement): Boolean
protected abstract fun isReferenceToWithoutExtensionChecking(candidateTarget: PsiElement): Boolean
override fun getRangeInElement(): TextRange { override fun getRangeInElement(): TextRange {
val element = element.getReferencedNameElement() val element = element.getReferencedNameElement()