Used analyze to multiple elements for copy/paste
This commit is contained in:
+1
@@ -50,6 +50,7 @@ internal class ResolutionFacadeImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun analyze(elements: Collection<KtElement>, bodyResolveMode: BodyResolveMode): BindingContext {
|
override fun analyze(elements: Collection<KtElement>, bodyResolveMode: BodyResolveMode): BindingContext {
|
||||||
|
if (elements.isEmpty()) return BindingContext.EMPTY
|
||||||
val resolveElementCache = getFrontendService(elements.first(), ResolveElementCache::class.java)
|
val resolveElementCache = getFrontendService(elements.first(), ResolveElementCache::class.java)
|
||||||
return resolveElementCache.resolveToElements(elements, bodyResolveMode)
|
return resolveElementCache.resolveToElements(elements, bodyResolveMode)
|
||||||
}
|
}
|
||||||
|
|||||||
+38
-23
@@ -33,7 +33,6 @@ import org.jetbrains.annotations.TestOnly
|
|||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference
|
||||||
import org.jetbrains.kotlin.idea.codeInsight.shorten.performDelayedShortening
|
import org.jetbrains.kotlin.idea.codeInsight.shorten.performDelayedShortening
|
||||||
@@ -48,11 +47,13 @@ import org.jetbrains.kotlin.idea.util.getFileResolutionScope
|
|||||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.elementsInRange
|
import org.jetbrains.kotlin.psi.psiUtil.elementsInRange
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.forEachDescendantOfType
|
import org.jetbrains.kotlin.psi.psiUtil.forEachDescendantOfType
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
||||||
import org.jetbrains.kotlin.resolve.scopes.utils.findFunction
|
import org.jetbrains.kotlin.resolve.scopes.utils.findFunction
|
||||||
import org.jetbrains.kotlin.resolve.scopes.utils.findVariable
|
import org.jetbrains.kotlin.resolve.scopes.utils.findVariable
|
||||||
@@ -122,28 +123,35 @@ class KotlinCopyPasteReferenceProcessor() : CopyPastePostProcessor<KotlinReferen
|
|||||||
startOffsets: IntArray,
|
startOffsets: IntArray,
|
||||||
endOffsets: IntArray
|
endOffsets: IntArray
|
||||||
): List<KotlinReferenceData> {
|
): List<KotlinReferenceData> {
|
||||||
|
val ranges = toTextRanges(startOffsets, endOffsets)
|
||||||
|
val elementsByRange = ranges.associateBy({ it }, { file.elementsInRange(it).filterIsInstance<KtElement>() })
|
||||||
|
|
||||||
|
val allElementsToResolve = elementsByRange.values.flatMap { it }.flatMap { it.collectDescendantsOfType<KtElement>() }
|
||||||
|
val bindingContext = file.getResolutionFacade().analyze(allElementsToResolve, BodyResolveMode.PARTIAL)
|
||||||
|
|
||||||
val result = ArrayList<KotlinReferenceData>()
|
val result = ArrayList<KotlinReferenceData>()
|
||||||
for (range in toTextRanges(startOffsets, endOffsets)) {
|
for ((range, elements) in elementsByRange) {
|
||||||
for (element in file.elementsInRange(range)) {
|
for (element in elements) {
|
||||||
result.addReferenceDataInsideElement(element, file, range.start, startOffsets, endOffsets)
|
result.addReferenceDataInsideElement(element, file, range.start, startOffsets, endOffsets, bindingContext)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun MutableCollection<KotlinReferenceData>.addReferenceDataInsideElement(
|
private fun MutableCollection<KotlinReferenceData>.addReferenceDataInsideElement(
|
||||||
element: PsiElement,
|
element: KtElement,
|
||||||
file: KtFile,
|
file: KtFile,
|
||||||
startOffset: Int,
|
startOffset: Int,
|
||||||
startOffsets: IntArray,
|
startOffsets: IntArray,
|
||||||
endOffsets: IntArray
|
endOffsets: IntArray,
|
||||||
|
bindingContext: BindingContext
|
||||||
) {
|
) {
|
||||||
if (PsiTreeUtil.getNonStrictParentOfType(element, *IGNORE_REFERENCES_INSIDE) != null) return
|
if (PsiTreeUtil.getNonStrictParentOfType(element, *IGNORE_REFERENCES_INSIDE) != null) return
|
||||||
|
|
||||||
element.forEachDescendantOfType<KtElement>(canGoInside = { it.javaClass as Class<*> !in IGNORE_REFERENCES_INSIDE }) { element ->
|
element.forEachDescendantOfType<KtElement>(canGoInside = { it.javaClass as Class<*> !in IGNORE_REFERENCES_INSIDE }) { element ->
|
||||||
val reference = element.mainReference ?: return@forEachDescendantOfType
|
val reference = element.mainReference ?: return@forEachDescendantOfType
|
||||||
|
|
||||||
val descriptors = resolveReference(reference)
|
val descriptors = resolveReference(reference, bindingContext)
|
||||||
//check whether this reference is unambiguous
|
//check whether this reference is unambiguous
|
||||||
if (reference !is KtMultiReference<*> && descriptors.size > 1) return@forEachDescendantOfType
|
if (reference !is KtMultiReference<*> && descriptors.size > 1) return@forEachDescendantOfType
|
||||||
|
|
||||||
@@ -183,7 +191,7 @@ class KotlinCopyPasteReferenceProcessor() : CopyPastePostProcessor<KotlinReferen
|
|||||||
|
|
||||||
val referenceData = values.single().data
|
val referenceData = values.single().data
|
||||||
|
|
||||||
processReferenceData(project, file, bounds.getStartOffset(), referenceData)
|
processReferenceData(project, file, bounds.startOffset, referenceData)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun processReferenceData(project: Project, file: KtFile, blockStart: Int, referenceData: Array<KotlinReferenceData>) {
|
fun processReferenceData(project: Project, file: KtFile, blockStart: Int, referenceData: Array<KotlinReferenceData>) {
|
||||||
@@ -202,11 +210,20 @@ class KotlinCopyPasteReferenceProcessor() : CopyPastePostProcessor<KotlinReferen
|
|||||||
private fun findReferencesToRestore(file: PsiFile, blockStart: Int, referenceData: Array<out KotlinReferenceData>): List<ReferenceToRestoreData> {
|
private fun findReferencesToRestore(file: PsiFile, blockStart: Int, referenceData: Array<out KotlinReferenceData>): List<ReferenceToRestoreData> {
|
||||||
if (file !is KtFile) return listOf()
|
if (file !is KtFile) return listOf()
|
||||||
|
|
||||||
|
val references = referenceData.map { it to findReference(it, file, blockStart) }
|
||||||
|
val bindingContext = try {
|
||||||
|
file.getResolutionFacade().analyze(references.mapNotNull { it.second?.element }, BodyResolveMode.PARTIAL)
|
||||||
|
}
|
||||||
|
catch (e: Throwable) {
|
||||||
|
LOG.error("Failed to analyze references after copy paste", e)
|
||||||
|
return emptyList()
|
||||||
|
}
|
||||||
val fileResolutionScope = file.getResolutionFacade().getFileResolutionScope(file)
|
val fileResolutionScope = file.getResolutionFacade().getFileResolutionScope(file)
|
||||||
return referenceData.mapNotNull {
|
return references.mapNotNull { pair ->
|
||||||
val reference = findReference(it, file, blockStart)
|
val data = pair.first
|
||||||
|
val reference = pair.second
|
||||||
if (reference != null)
|
if (reference != null)
|
||||||
createReferenceToRestoreData(reference, it, file, fileResolutionScope)
|
createReferenceToRestoreData(reference, data, file, fileResolutionScope, bindingContext)
|
||||||
else
|
else
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
@@ -227,7 +244,13 @@ class KotlinCopyPasteReferenceProcessor() : CopyPastePostProcessor<KotlinReferen
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createReferenceToRestoreData(reference: KtReference, refData: KotlinReferenceData, file: KtFile, fileResolutionScope: LexicalScope): ReferenceToRestoreData? {
|
private fun createReferenceToRestoreData(
|
||||||
|
reference: KtReference,
|
||||||
|
refData: KotlinReferenceData,
|
||||||
|
file: KtFile,
|
||||||
|
fileResolutionScope: LexicalScope,
|
||||||
|
bindingContext: BindingContext
|
||||||
|
): ReferenceToRestoreData? {
|
||||||
val originalFqName = FqName(refData.fqName)
|
val originalFqName = FqName(refData.fqName)
|
||||||
val name = originalFqName.shortName()
|
val name = originalFqName.shortName()
|
||||||
|
|
||||||
@@ -242,13 +265,7 @@ class KotlinCopyPasteReferenceProcessor() : CopyPastePostProcessor<KotlinReferen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val referencedDescriptors = try {
|
val referencedDescriptors = resolveReference(reference, bindingContext)
|
||||||
resolveReference(reference)
|
|
||||||
}
|
|
||||||
catch (e: Throwable) {
|
|
||||||
LOG.error("Failed to analyze reference ($reference) after copy paste", e)
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
val referencedFqNames = referencedDescriptors
|
val referencedFqNames = referencedDescriptors
|
||||||
.filterNot { ErrorUtils.isError(it) }
|
.filterNot { ErrorUtils.isError(it) }
|
||||||
.mapNotNull { it.importableFqName }
|
.mapNotNull { it.importableFqName }
|
||||||
@@ -263,10 +280,8 @@ class KotlinCopyPasteReferenceProcessor() : CopyPastePostProcessor<KotlinReferen
|
|||||||
return ReferenceToRestoreData(reference, refData)
|
return ReferenceToRestoreData(reference, refData)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun resolveReference(reference: KtReference): Collection<DeclarationDescriptor> {
|
private fun resolveReference(reference: KtReference, bindingContext: BindingContext): Collection<DeclarationDescriptor> {
|
||||||
val element = reference.element
|
val element = reference.element
|
||||||
val bindingContext = element.analyze() //TODO: we could use partial body resolve for all references together
|
|
||||||
|
|
||||||
if (element is KtNameReferenceExpression && reference is KtSimpleNameReference) {
|
if (element is KtNameReferenceExpression && reference is KtSimpleNameReference) {
|
||||||
bindingContext[BindingContext.SHORT_REFERENCE_TO_COMPANION_OBJECT, element]
|
bindingContext[BindingContext.SHORT_REFERENCE_TO_COMPANION_OBJECT, element]
|
||||||
?.let { return listOf(it) }
|
?.let { return listOf(it) }
|
||||||
@@ -290,7 +305,7 @@ class KotlinCopyPasteReferenceProcessor() : CopyPastePostProcessor<KotlinReferen
|
|||||||
val fqName = FqName(refData.fqName)
|
val fqName = FqName(refData.fqName)
|
||||||
|
|
||||||
if (!refData.kind.isExtension() && reference is KtSimpleNameReference) {
|
if (!refData.kind.isExtension() && reference is KtSimpleNameReference) {
|
||||||
val pointer = smartPointerManager.createSmartPsiElementPointer(reference.getElement(), file)
|
val pointer = smartPointerManager.createSmartPsiElementPointer(reference.element, file)
|
||||||
bindingRequests.add(BindingRequest(pointer, fqName))
|
bindingRequests.add(BindingRequest(pointer, fqName))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user