KotlinCopyPasteReferenceProcessor: cleanup code
This commit is contained in:
+58
-57
@@ -74,8 +74,8 @@ class KotlinCopyPasteReferenceProcessor : CopyPastePostProcessor<KotlinReference
|
|||||||
private val LOG = Logger.getInstance(KotlinCopyPasteReferenceProcessor::class.java)
|
private val LOG = Logger.getInstance(KotlinCopyPasteReferenceProcessor::class.java)
|
||||||
|
|
||||||
private val IGNORE_REFERENCES_INSIDE: Array<Class<out KtElement>> = arrayOf(
|
private val IGNORE_REFERENCES_INSIDE: Array<Class<out KtElement>> = arrayOf(
|
||||||
KtImportList::class.java,
|
KtImportList::class.java,
|
||||||
KtPackageDirective::class.java
|
KtPackageDirective::class.java
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun extractTransferableData(content: Transferable): List<KotlinReferenceTransferableData> {
|
override fun extractTransferableData(content: Transferable): List<KotlinReferenceTransferableData> {
|
||||||
@@ -85,10 +85,8 @@ class KotlinCopyPasteReferenceProcessor : CopyPastePostProcessor<KotlinReference
|
|||||||
val data = content.getTransferData(flavor) as? KotlinReferenceTransferableData ?: return listOf()
|
val data = content.getTransferData(flavor) as? KotlinReferenceTransferableData ?: return listOf()
|
||||||
// copy to prevent changing of original by convertLineSeparators
|
// copy to prevent changing of original by convertLineSeparators
|
||||||
return listOf(data.clone())
|
return listOf(data.clone())
|
||||||
}
|
} catch (ignored: UnsupportedFlavorException) {
|
||||||
catch (ignored: UnsupportedFlavorException) {
|
} catch (ignored: IOException) {
|
||||||
}
|
|
||||||
catch (ignored: IOException) {
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,23 +94,21 @@ class KotlinCopyPasteReferenceProcessor : CopyPastePostProcessor<KotlinReference
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun collectTransferableData(
|
override fun collectTransferableData(
|
||||||
file: PsiFile,
|
file: PsiFile,
|
||||||
editor: Editor,
|
editor: Editor,
|
||||||
startOffsets: IntArray,
|
startOffsets: IntArray,
|
||||||
endOffsets: IntArray
|
endOffsets: IntArray
|
||||||
): List<KotlinReferenceTransferableData> {
|
): List<KotlinReferenceTransferableData> {
|
||||||
if (file !is KtFile || DumbService.getInstance(file.getProject()).isDumb) return listOf()
|
if (file !is KtFile || DumbService.getInstance(file.getProject()).isDumb) return listOf()
|
||||||
|
|
||||||
val collectedData = try {
|
val collectedData = try {
|
||||||
collectReferenceData(file, startOffsets, endOffsets)
|
collectReferenceData(file, startOffsets, endOffsets)
|
||||||
}
|
} catch (e: ProcessCanceledException) {
|
||||||
catch (e: ProcessCanceledException) {
|
|
||||||
// supposedly analysis can only be canceled from another thread
|
// supposedly analysis can only be canceled from another thread
|
||||||
// do not log ProcessCanceledException as it is rethrown by IdeaLogger and code won't be copied
|
// do not log ProcessCanceledException as it is rethrown by IdeaLogger and code won't be copied
|
||||||
LOG.debug("ProcessCanceledException while analyzing references in ${file.getName()}. References can't be processed.")
|
LOG.debug("ProcessCanceledException while analyzing references in ${file.getName()}. References can't be processed.")
|
||||||
return listOf()
|
return listOf()
|
||||||
}
|
} catch (e: Throwable) {
|
||||||
catch (e: Throwable) {
|
|
||||||
LOG.error("Exception in processing references for copy paste in file ${file.getName()}}", e)
|
LOG.error("Exception in processing references for copy paste in file ${file.getName()}}", e)
|
||||||
return listOf()
|
return listOf()
|
||||||
}
|
}
|
||||||
@@ -123,13 +119,13 @@ class KotlinCopyPasteReferenceProcessor : CopyPastePostProcessor<KotlinReference
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun collectReferenceData(
|
fun collectReferenceData(
|
||||||
file: KtFile,
|
file: KtFile,
|
||||||
startOffsets: IntArray,
|
startOffsets: IntArray,
|
||||||
endOffsets: IntArray
|
endOffsets: IntArray
|
||||||
): List<KotlinReferenceData> {
|
): List<KotlinReferenceData> {
|
||||||
val ranges = toTextRanges(startOffsets, endOffsets)
|
val ranges = toTextRanges(startOffsets, endOffsets)
|
||||||
val elementsByRange = ranges.associateBy({ it }, {
|
val elementsByRange = ranges.associateBy({ it }, { textRange ->
|
||||||
file.elementsInRange(it).filter { it is KtElement || it is KDocElement }
|
file.elementsInRange(textRange).filter { it is KtElement || it is KDocElement }
|
||||||
})
|
})
|
||||||
|
|
||||||
val allElementsToResolve = elementsByRange.values.flatten().flatMap { it.collectDescendantsOfType<KtElement>() }
|
val allElementsToResolve = elementsByRange.values.flatten().flatMap { it.collectDescendantsOfType<KtElement>() }
|
||||||
@@ -148,12 +144,12 @@ class KotlinCopyPasteReferenceProcessor : CopyPastePostProcessor<KotlinReference
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun MutableCollection<KotlinReferenceData>.addReferenceDataInsideElement(
|
private fun MutableCollection<KotlinReferenceData>.addReferenceDataInsideElement(
|
||||||
element: PsiElement,
|
element: PsiElement,
|
||||||
file: KtFile,
|
file: KtFile,
|
||||||
startOffset: Int,
|
startOffset: Int,
|
||||||
startOffsets: IntArray,
|
startOffsets: IntArray,
|
||||||
endOffsets: IntArray,
|
endOffsets: IntArray,
|
||||||
bindingContext: BindingContext
|
bindingContext: BindingContext
|
||||||
) {
|
) {
|
||||||
if (PsiTreeUtil.getNonStrictParentOfType(element, *IGNORE_REFERENCES_INSIDE) != null) return
|
if (PsiTreeUtil.getNonStrictParentOfType(element, *IGNORE_REFERENCES_INSIDE) != null) return
|
||||||
|
|
||||||
@@ -167,8 +163,8 @@ class KotlinCopyPasteReferenceProcessor : CopyPastePostProcessor<KotlinReference
|
|||||||
for (descriptor in descriptors) {
|
for (descriptor in descriptors) {
|
||||||
val effectiveReferencedDescriptors = DescriptorToSourceUtils.getEffectiveReferencedDescriptors(descriptor).asSequence()
|
val effectiveReferencedDescriptors = DescriptorToSourceUtils.getEffectiveReferencedDescriptors(descriptor).asSequence()
|
||||||
val declaration = effectiveReferencedDescriptors
|
val declaration = effectiveReferencedDescriptors
|
||||||
.map { DescriptorToSourceUtils.getSourceFromDescriptor(it) }
|
.map { DescriptorToSourceUtils.getSourceFromDescriptor(it) }
|
||||||
.singleOrNull()
|
.singleOrNull()
|
||||||
if (declaration != null && declaration.isInCopiedArea(file, startOffsets, endOffsets)) continue
|
if (declaration != null && declaration.isInCopiedArea(file, startOffsets, endOffsets)) continue
|
||||||
|
|
||||||
if (!reference.canBeResolvedViaImport(descriptor, bindingContext)) continue
|
if (!reference.canBeResolvedViaImport(descriptor, bindingContext)) continue
|
||||||
@@ -184,17 +180,17 @@ class KotlinCopyPasteReferenceProcessor : CopyPastePostProcessor<KotlinReference
|
|||||||
}
|
}
|
||||||
|
|
||||||
private data class ReferenceToRestoreData(
|
private data class ReferenceToRestoreData(
|
||||||
val reference: KtReference,
|
val reference: KtReference,
|
||||||
val refData: KotlinReferenceData
|
val refData: KotlinReferenceData
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun processTransferableData(
|
override fun processTransferableData(
|
||||||
project: Project,
|
project: Project,
|
||||||
editor: Editor,
|
editor: Editor,
|
||||||
bounds: RangeMarker,
|
bounds: RangeMarker,
|
||||||
caretOffset: Int,
|
caretOffset: Int,
|
||||||
indented: Ref<Boolean>,
|
indented: Ref<Boolean>,
|
||||||
values: List<KotlinReferenceTransferableData>
|
values: List<KotlinReferenceTransferableData>
|
||||||
) {
|
) {
|
||||||
if (DumbService.getInstance(project).isDumb) return
|
if (DumbService.getInstance(project).isDumb) return
|
||||||
|
|
||||||
@@ -220,14 +216,17 @@ class KotlinCopyPasteReferenceProcessor : CopyPastePostProcessor<KotlinReference
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 references = referenceData.map { it to findReference(it, file, blockStart) }
|
||||||
val bindingContext = try {
|
val bindingContext = try {
|
||||||
file.getResolutionFacade().analyze(references.mapNotNull { it.second?.element }, BodyResolveMode.PARTIAL)
|
file.getResolutionFacade().analyze(references.mapNotNull { it.second?.element }, BodyResolveMode.PARTIAL)
|
||||||
}
|
} catch (e: Throwable) {
|
||||||
catch (e: Throwable) {
|
|
||||||
LOG.error("Failed to analyze references after copy paste", e)
|
LOG.error("Failed to analyze references after copy paste", e)
|
||||||
return emptyList()
|
return emptyList()
|
||||||
}
|
}
|
||||||
@@ -258,11 +257,11 @@ class KotlinCopyPasteReferenceProcessor : CopyPastePostProcessor<KotlinReference
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun createReferenceToRestoreData(
|
private fun createReferenceToRestoreData(
|
||||||
reference: KtReference,
|
reference: KtReference,
|
||||||
refData: KotlinReferenceData,
|
refData: KotlinReferenceData,
|
||||||
file: KtFile,
|
file: KtFile,
|
||||||
fileResolutionScope: LexicalScope,
|
fileResolutionScope: LexicalScope,
|
||||||
bindingContext: BindingContext
|
bindingContext: BindingContext
|
||||||
): ReferenceToRestoreData? {
|
): ReferenceToRestoreData? {
|
||||||
val originalFqName = FqName(refData.fqName)
|
val originalFqName = FqName(refData.fqName)
|
||||||
val name = originalFqName.shortName()
|
val name = originalFqName.shortName()
|
||||||
@@ -272,8 +271,7 @@ class KotlinCopyPasteReferenceProcessor : CopyPastePostProcessor<KotlinReference
|
|||||||
if (fileResolutionScope.findFunction(name, NoLookupLocation.FROM_IDE) { it.importableFqName == originalFqName } != null) {
|
if (fileResolutionScope.findFunction(name, NoLookupLocation.FROM_IDE) { it.importableFqName == originalFqName } != null) {
|
||||||
return null // already imported
|
return null // already imported
|
||||||
}
|
}
|
||||||
}
|
} else if (refData.kind == KotlinReferenceData.Kind.PROPERTY) {
|
||||||
else if (refData.kind == KotlinReferenceData.Kind.PROPERTY) {
|
|
||||||
if (fileResolutionScope.findVariable(name, NoLookupLocation.FROM_IDE) { it.importableFqName == originalFqName } != null) {
|
if (fileResolutionScope.findVariable(name, NoLookupLocation.FROM_IDE) { it.importableFqName == originalFqName } != null) {
|
||||||
return null // already imported
|
return null // already imported
|
||||||
}
|
}
|
||||||
@@ -282,9 +280,9 @@ class KotlinCopyPasteReferenceProcessor : CopyPastePostProcessor<KotlinReference
|
|||||||
|
|
||||||
val referencedDescriptors = resolveReference(reference, bindingContext)
|
val referencedDescriptors = resolveReference(reference, bindingContext)
|
||||||
val referencedFqNames = referencedDescriptors
|
val referencedFqNames = referencedDescriptors
|
||||||
.filterNot { ErrorUtils.isError(it) }
|
.filterNot { ErrorUtils.isError(it) }
|
||||||
.mapNotNull { it.importableFqName }
|
.mapNotNull { it.importableFqName }
|
||||||
.toSet()
|
.toSet()
|
||||||
if (referencedFqNames.singleOrNull() == originalFqName) return null
|
if (referencedFqNames.singleOrNull() == originalFqName) return null
|
||||||
|
|
||||||
// check that descriptor to import exists and is accessible from the current module
|
// check that descriptor to import exists and is accessible from the current module
|
||||||
@@ -299,7 +297,7 @@ class KotlinCopyPasteReferenceProcessor : CopyPastePostProcessor<KotlinReference
|
|||||||
val element = reference.element
|
val element = reference.element
|
||||||
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) }
|
||||||
}
|
}
|
||||||
|
|
||||||
return reference.resolveToDescriptors(bindingContext)
|
return reference.resolveToDescriptors(bindingContext)
|
||||||
@@ -310,8 +308,8 @@ class KotlinCopyPasteReferenceProcessor : CopyPastePostProcessor<KotlinReference
|
|||||||
val smartPointerManager = SmartPointerManager.getInstance(file.project)
|
val smartPointerManager = SmartPointerManager.getInstance(file.project)
|
||||||
|
|
||||||
data class BindingRequest(
|
data class BindingRequest(
|
||||||
val pointer: SmartPsiElementPointer<KtSimpleNameExpression>,
|
val pointer: SmartPsiElementPointer<KtSimpleNameExpression>,
|
||||||
val fqName: FqName
|
val fqName: FqName
|
||||||
)
|
)
|
||||||
|
|
||||||
val bindingRequests = ArrayList<BindingRequest>()
|
val bindingRequests = ArrayList<BindingRequest>()
|
||||||
@@ -324,8 +322,7 @@ class KotlinCopyPasteReferenceProcessor : CopyPastePostProcessor<KotlinReference
|
|||||||
if (reference is KtSimpleNameReference) {
|
if (reference is KtSimpleNameReference) {
|
||||||
val pointer = smartPointerManager.createSmartPsiElementPointer(reference.element, file)
|
val pointer = smartPointerManager.createSmartPsiElementPointer(reference.element, file)
|
||||||
bindingRequests.add(BindingRequest(pointer, fqName))
|
bindingRequests.add(BindingRequest(pointer, fqName))
|
||||||
}
|
} else if (reference is KDocReference) {
|
||||||
else if (reference is KDocReference) {
|
|
||||||
descriptorsToImport.addAll(findImportableDescriptors(fqName, file))
|
descriptorsToImport.addAll(findImportableDescriptors(fqName, file))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -350,10 +347,13 @@ class KotlinCopyPasteReferenceProcessor : CopyPastePostProcessor<KotlinReference
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun findCallableToImport(fqName: FqName, file: KtFile): CallableDescriptor?
|
private fun findCallableToImport(fqName: FqName, file: KtFile): CallableDescriptor? =
|
||||||
= findImportableDescriptors(fqName, file).firstIsInstanceOrNull<CallableDescriptor>()
|
findImportableDescriptors(fqName, file).firstIsInstanceOrNull()
|
||||||
|
|
||||||
private fun showRestoreReferencesDialog(project: Project, referencesToRestore: List<ReferenceToRestoreData>): Collection<ReferenceToRestoreData> {
|
private fun showRestoreReferencesDialog(
|
||||||
|
project: Project,
|
||||||
|
referencesToRestore: List<ReferenceToRestoreData>
|
||||||
|
): Collection<ReferenceToRestoreData> {
|
||||||
val fqNames = referencesToRestore.asSequence().map { it.refData.fqName }.toSortedSet()
|
val fqNames = referencesToRestore.asSequence().map { it.refData.fqName }.toSortedSet()
|
||||||
|
|
||||||
if (ApplicationManager.getApplication().isUnitTestMode) {
|
if (ApplicationManager.getApplication().isUnitTestMode) {
|
||||||
@@ -383,6 +383,7 @@ class KotlinCopyPasteReferenceProcessor : CopyPastePostProcessor<KotlinReference
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@get:TestOnly var declarationsToImportSuggested: Collection<String> = emptyList()
|
@get:TestOnly
|
||||||
|
var declarationsToImportSuggested: Collection<String> = emptyList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user