Working on new imports insertion on copy/paste
This commit is contained in:
+8
-5
@@ -22,11 +22,12 @@ import org.jetbrains.kotlin.psi.JetElement
|
||||
import org.jetbrains.kotlin.psi.UserDataProperty
|
||||
import com.intellij.openapi.util.Key
|
||||
import org.jetbrains.kotlin.psi.NotNullableUserDataProperty
|
||||
import java.util.HashSet
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.psi.SmartPointerManager
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import org.jetbrains.kotlin.idea.util.ShortenReferences.Options
|
||||
import org.jetbrains.kotlin.idea.util.ShortenReferences
|
||||
import java.util.*
|
||||
|
||||
class ShorteningRequest(val pointer: SmartPsiElementPointer<JetElement>, val options: Options)
|
||||
|
||||
@@ -43,7 +44,7 @@ public var Project.ensureElementsToShortenIsEmptyBeforeRefactoring: Boolean
|
||||
private fun Project.getOrCreateElementsToShorten(): MutableSet<ShorteningRequest> {
|
||||
var elements = elementsToShorten
|
||||
if (elements == null) {
|
||||
elements = HashSet()
|
||||
elements = LinkedHashSet()
|
||||
elementsToShorten = elements
|
||||
}
|
||||
|
||||
@@ -57,12 +58,14 @@ public fun JetElement.addToShorteningWaitSet(options: Options = Options.DEFAULT)
|
||||
project.getOrCreateElementsToShorten().add(ShorteningRequest(elementPointer, options))
|
||||
}
|
||||
|
||||
public fun withElementsToShorten(project: Project, f: (Set<ShorteningRequest>) -> Unit) {
|
||||
public fun performDelayedShortening(project: Project) {
|
||||
project.elementsToShorten?.let { requests ->
|
||||
project.elementsToShorten = null
|
||||
f(requests)
|
||||
val elements = requests.map { it.pointer.getElement() }
|
||||
val options = requests.map { it.options }
|
||||
val elementToOptions = (elements zip options).toMap()
|
||||
ShortenReferences({ elementToOptions[it] ?: ShortenReferences.Options.DEFAULT }).process(elements.filterNotNull())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private val LOG = Logger.getInstance(javaClass<Project>().getCanonicalName())
|
||||
|
||||
+115
-140
@@ -16,54 +16,42 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.codeInsight
|
||||
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.codeInsight.editorActions.ReferenceData
|
||||
import java.util.ArrayList
|
||||
import com.intellij.openapi.editor.RangeMarker
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.codeInsight.editorActions.ReferenceTransferableData
|
||||
import com.intellij.codeInsight.daemon.impl.CollectHighlightsUtil
|
||||
import org.jetbrains.kotlin.psi.JetFile
|
||||
import org.jetbrains.kotlin.idea.util.ImportInsertHelper
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.Ref
|
||||
import com.intellij.openapi.project.DumbService
|
||||
import com.intellij.psi.PsiDocumentManager
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import java.awt.datatransfer.Transferable
|
||||
import com.intellij.codeInsight.CodeInsightSettings
|
||||
import com.intellij.codeInsight.editorActions.CopyPastePostProcessor
|
||||
import org.jetbrains.kotlin.idea.references.JetReference
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import org.jetbrains.kotlin.psi.JetPsiFactory
|
||||
import org.jetbrains.kotlin.psi.JetSimpleNameExpression
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.kotlin.psi.JetCallExpression
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
import org.jetbrains.kotlin.psi.JetImportDirective
|
||||
import org.jetbrains.kotlin.psi.JetPackageDirective
|
||||
import org.jetbrains.kotlin.idea.references.JetMultiReference
|
||||
import org.jetbrains.kotlin.psi.JetElement
|
||||
import org.jetbrains.kotlin.idea.conversion.copy.*
|
||||
import java.awt.datatransfer.UnsupportedFlavorException
|
||||
import java.io.IOException
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import org.jetbrains.kotlin.psi.JetDotQualifiedExpression
|
||||
import org.jetbrains.kotlin.psi.JetUserType
|
||||
import org.jetbrains.kotlin.psi.JetTypeReference
|
||||
import org.jetbrains.kotlin.idea.imports.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getReceiverExpression
|
||||
import org.jetbrains.kotlin.utils.*
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
|
||||
import com.intellij.openapi.progress.ProcessCanceledException
|
||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
import org.jetbrains.kotlin.idea.references.*
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.resolve.QualifiedExpressionResolver.LookupMode
|
||||
import org.jetbrains.kotlin.resolve.*
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.*
|
||||
import org.jetbrains.kotlin.idea.util.*
|
||||
import org.jetbrains.kotlin.utils.*
|
||||
import org.jetbrains.kotlin.idea.codeInsight.shorten.performDelayedShortening
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.*
|
||||
import com.intellij.psi.*
|
||||
import java.util.*
|
||||
|
||||
//NOTE: this class is based on CopyPasteReferenceProcessor and JavaCopyPasteReferenceProcessor
|
||||
public class KotlinCopyPasteReferenceProcessor() : CopyPastePostProcessor<ReferenceTransferableData>() {
|
||||
public class KotlinCopyPasteReferenceProcessor() : CopyPastePostProcessor<KotlinReferenceTransferableData>() {
|
||||
private val LOG = Logger.getInstance(javaClass<KotlinCopyPasteReferenceProcessor>())
|
||||
|
||||
private val IGNORE_REFERENCES_INSIDE: Array<Class<out JetElement>?> = array(
|
||||
@@ -71,17 +59,13 @@ public class KotlinCopyPasteReferenceProcessor() : CopyPastePostProcessor<Refere
|
||||
javaClass<JetPackageDirective>()
|
||||
)
|
||||
|
||||
override fun extractTransferableData(content: Transferable): List<ReferenceTransferableData> {
|
||||
override fun extractTransferableData(content: Transferable): List<KotlinReferenceTransferableData> {
|
||||
if (CodeInsightSettings.getInstance().ADD_IMPORTS_ON_PASTE != CodeInsightSettings.NO) {
|
||||
try {
|
||||
val flavor = ReferenceData.getDataFlavor()
|
||||
if (flavor != null) {
|
||||
val referenceData = content.getTransferData(flavor) as? ReferenceTransferableData
|
||||
if (referenceData != null) {
|
||||
// copy to prevent changing of original by convertLineSeparators
|
||||
return listOf(referenceData.clone())
|
||||
}
|
||||
}
|
||||
val flavor = KotlinReferenceData.dataFlavor ?: return listOf()
|
||||
val data = content.getTransferData(flavor) as? KotlinReferenceTransferableData ?: return listOf()
|
||||
// copy to prevent changing of original by convertLineSeparators
|
||||
return listOf(data.clone())
|
||||
}
|
||||
catch (ignored: UnsupportedFlavorException) {
|
||||
}
|
||||
@@ -97,7 +81,7 @@ public class KotlinCopyPasteReferenceProcessor() : CopyPastePostProcessor<Refere
|
||||
editor: Editor,
|
||||
startOffsets: IntArray,
|
||||
endOffsets: IntArray
|
||||
): List<ReferenceTransferableData> {
|
||||
): List<KotlinReferenceTransferableData> {
|
||||
if (file !is JetFile || DumbService.getInstance(file.getProject()).isDumb()) return listOf()
|
||||
|
||||
val collectedData = try {
|
||||
@@ -120,7 +104,7 @@ public class KotlinCopyPasteReferenceProcessor() : CopyPastePostProcessor<Refere
|
||||
|
||||
if (collectedData.isEmpty()) return listOf()
|
||||
|
||||
return listOf(ReferenceTransferableData(collectedData.copyToArray()))
|
||||
return listOf(KotlinReferenceTransferableData(collectedData.copyToArray()))
|
||||
}
|
||||
|
||||
private fun collectReferenceDataFromElement(
|
||||
@@ -129,44 +113,51 @@ public class KotlinCopyPasteReferenceProcessor() : CopyPastePostProcessor<Refere
|
||||
startOffset: Int,
|
||||
startOffsets: IntArray,
|
||||
endOffsets: IntArray
|
||||
): Collection<ReferenceData> {
|
||||
): Collection<KotlinReferenceData> {
|
||||
|
||||
fun collectReferenceData(referencedDeclaration: PsiElement, referencedDescriptor: DeclarationDescriptor): ReferenceData? {
|
||||
if (referencedDeclaration.isInCopiedArea(file, startOffsets, endOffsets)) return null
|
||||
if (isInReceiverScope(element, referencedDescriptor)) return null
|
||||
if (PsiTreeUtil.getParentOfType(element, *IGNORE_REFERENCES_INSIDE) != null) return listOf()
|
||||
|
||||
val fqName = referencedDescriptor.importableFqName
|
||||
if (fqName != null && referencedDescriptor.canBeReferencedViaImport()) {
|
||||
return createReferenceData(element, startOffset, fqName)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
val isInsideIgnoredElement = PsiTreeUtil.getParentOfType(element, *IGNORE_REFERENCES_INSIDE) != null
|
||||
if (isInsideIgnoredElement) return listOf()
|
||||
|
||||
val reference = element.getReference()
|
||||
if (reference !is JetReference) return listOf()
|
||||
val reference = element.getReference() as? JetReference ?: return listOf()
|
||||
|
||||
val resolveMap = reference.resolveMap()
|
||||
//check whether this reference is unambiguous
|
||||
if (reference !is JetMultiReference<*> && resolveMap.size() > 1) return listOf()
|
||||
val collectedData = ArrayList<ReferenceData>()
|
||||
for ((referencedDescriptor, declarations) in resolveMap) {
|
||||
if (declarations.size() != 1) continue
|
||||
collectedData.addIfNotNull(collectReferenceData(declarations.first(), referencedDescriptor))
|
||||
|
||||
val collectedData = ArrayList<KotlinReferenceData>()
|
||||
for ((descriptor, declarations) in resolveMap) {
|
||||
val declaration = declarations.singleOrNull() ?: continue
|
||||
if (declaration.isInCopiedArea(file, startOffsets, endOffsets)) continue
|
||||
|
||||
if (!descriptor.isExtension) {
|
||||
if (element !is JetNameReferenceExpression) continue
|
||||
if (element.getIdentifier() == null) continue // skip 'this' etc
|
||||
if (element.getReceiverExpression() != null) continue
|
||||
}
|
||||
|
||||
val fqName = descriptor.importableFqName ?: continue
|
||||
if (!descriptor.canBeReferencedViaImport()) continue
|
||||
|
||||
val kind = when (descriptor.getImportableDescriptor()) {
|
||||
is ClassDescriptor ->
|
||||
KotlinReferenceData.Kind.CLASS
|
||||
|
||||
is PackageViewDescriptor ->
|
||||
KotlinReferenceData.Kind.PACKAGE
|
||||
|
||||
is CallableDescriptor ->
|
||||
if (descriptor.isExtension) KotlinReferenceData.Kind.EXTENSION_CALLABLE else KotlinReferenceData.Kind.NON_EXTENSION_CALLABLE
|
||||
|
||||
else ->
|
||||
continue
|
||||
}
|
||||
collectedData.add(KotlinReferenceData(element.range.start - startOffset, element.range.end - startOffset, fqName.asString(), kind))
|
||||
}
|
||||
return collectedData
|
||||
}
|
||||
|
||||
private fun createReferenceData(element: PsiElement, startOffset: Int, fqName: FqName)
|
||||
= ReferenceData(element.range.start - startOffset, element.range.end - startOffset, fqName.asString(), null)
|
||||
|
||||
private data class ReferenceToRestoreData(
|
||||
val expression: JetElement,
|
||||
val fqName: FqName,
|
||||
val lengthenReference: Boolean = false
|
||||
val reference: JetReference,
|
||||
val refData: KotlinReferenceData
|
||||
)
|
||||
|
||||
override fun processTransferableData (
|
||||
@@ -175,7 +166,7 @@ public class KotlinCopyPasteReferenceProcessor() : CopyPastePostProcessor<Refere
|
||||
bounds: RangeMarker,
|
||||
caretOffset: Int,
|
||||
indented: Ref<Boolean>,
|
||||
values: List<ReferenceTransferableData>
|
||||
values: List<KotlinReferenceTransferableData>
|
||||
) {
|
||||
if (DumbService.getInstance(project).isDumb()) return
|
||||
|
||||
@@ -187,7 +178,7 @@ public class KotlinCopyPasteReferenceProcessor() : CopyPastePostProcessor<Refere
|
||||
|
||||
assert(values.size() == 1)
|
||||
|
||||
val referenceData = values.single().getData()!!
|
||||
val referenceData = values.single().data
|
||||
val referencesPossibleToRestore = findReferencesToRestore(file, bounds, referenceData)
|
||||
|
||||
val selectedReferencesToRestore = showRestoreReferencesDialog(project, referencesPossibleToRestore)
|
||||
@@ -199,24 +190,19 @@ public class KotlinCopyPasteReferenceProcessor() : CopyPastePostProcessor<Refere
|
||||
PsiDocumentManager.getInstance(project).commitAllDocuments()
|
||||
}
|
||||
|
||||
private fun findReferencesToRestore(file: PsiFile, bounds: RangeMarker, referenceData: Array<out ReferenceData>): List<ReferenceToRestoreData> {
|
||||
private fun findReferencesToRestore(file: PsiFile, bounds: RangeMarker, referenceData: Array<out KotlinReferenceData>): List<ReferenceToRestoreData> {
|
||||
if (file !is JetFile) return listOf()
|
||||
|
||||
return referenceData.map {
|
||||
if (ImportInsertHelper.getInstance(file.getProject()).needImport(it.fqName, file)) {
|
||||
val referenceExpression = findReference(it, file, bounds)
|
||||
if (referenceExpression != null)
|
||||
createReferenceToRestoreData(referenceExpression, it.fqName)
|
||||
else
|
||||
null
|
||||
}
|
||||
else {
|
||||
val referenceElement = findReference(it, file, bounds)
|
||||
if (referenceElement != null)
|
||||
createReferenceToRestoreData(referenceElement, it)
|
||||
else
|
||||
null
|
||||
}
|
||||
}.filterNotNull()
|
||||
}
|
||||
|
||||
private fun findReference(data: ReferenceData, file: JetFile, bounds: RangeMarker): JetElement? {
|
||||
private fun findReference(data: KotlinReferenceData, file: JetFile, bounds: RangeMarker): JetElement? {
|
||||
val startOffset = data.startOffset + bounds.getStartOffset()
|
||||
val endOffset = data.endOffset + bounds.getStartOffset()
|
||||
val element = file.findElementAt(startOffset)
|
||||
@@ -237,47 +223,65 @@ public class KotlinCopyPasteReferenceProcessor() : CopyPastePostProcessor<Refere
|
||||
return null
|
||||
}
|
||||
|
||||
private fun createReferenceToRestoreData(expression: JetElement, originalReferencedFqName: FqName): ReferenceToRestoreData? {
|
||||
val reference = expression.getReference() as? JetReference ?: return null
|
||||
private fun createReferenceToRestoreData(element: JetElement, refData: KotlinReferenceData): ReferenceToRestoreData? {
|
||||
val reference = element.getReference() as? JetReference ?: return null
|
||||
val referencedDescriptors = try {
|
||||
reference.resolveToDescriptors()
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
LOG.error("Failed to analyze reference (${expression.getText()}) after copy paste", e)
|
||||
LOG.error("Failed to analyze reference (${element.getText()}) after copy paste", e)
|
||||
return null
|
||||
}
|
||||
val referencedFqNames = referencedDescriptors.filterNot { ErrorUtils.isError(it) } .map { it.importableFqName }
|
||||
val referencesSame = referencedFqNames any { it == originalReferencedFqName }
|
||||
val conflict = referencedFqNames any { it != originalReferencedFqName && (it?.shortName() == originalReferencedFqName.shortName()) }
|
||||
when {
|
||||
referencesSame && !conflict -> {
|
||||
return null
|
||||
}
|
||||
|
||||
!referencesSame && !conflict -> {
|
||||
return ReferenceToRestoreData(expression, originalReferencedFqName)
|
||||
}
|
||||
|
||||
conflict -> {
|
||||
val mustBeReferencedWithReceiver = referencedDescriptors.any { it.isExtension }
|
||||
if (!mustBeReferencedWithReceiver && canLengthenReferenceExpression(expression, originalReferencedFqName)) {
|
||||
return ReferenceToRestoreData(expression, originalReferencedFqName, lengthenReference = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
val referencedFqNames = referencedDescriptors.filterNot { ErrorUtils.isError(it) }.map { it.importableFqName }.filterNotNull()
|
||||
val originalFqName = FqName(refData.fqName)
|
||||
val referencesSame = referencedFqNames.any { it == originalFqName }
|
||||
val conflict = referencedFqNames.any { it != originalFqName && it.shortName() == originalFqName.shortName() }
|
||||
if (referencesSame && !conflict) return null
|
||||
return ReferenceToRestoreData(reference, refData)
|
||||
}
|
||||
|
||||
private fun restoreReferences(referencesToRestore: Collection<ReferenceToRestoreData>, file: JetFile) {
|
||||
for ((referenceExpression, fqName, shouldLengthen) in referencesToRestore) {
|
||||
if (!shouldLengthen) {
|
||||
ImportInsertHelper.getInstance(file.getProject()).addImportDirectiveIfNeeded(fqName, file)
|
||||
val importHelper = ImportInsertHelper.getInstance(file.getProject())
|
||||
val smartPointerManager = SmartPointerManager.getInstance(file.getProject())
|
||||
|
||||
[data] class BindingRequest(
|
||||
val pointer: SmartPsiElementPointer<JetSimpleNameExpression>,
|
||||
val fqName: FqName
|
||||
)
|
||||
|
||||
val bindingRequests = ArrayList<BindingRequest>()
|
||||
val descriptorsToImport = ArrayList<CallableDescriptor>()
|
||||
for ((reference, refData) in referencesToRestore) {
|
||||
val fqName = FqName(refData.fqName)
|
||||
|
||||
if (refData.kind != KotlinReferenceData.Kind.EXTENSION_CALLABLE && reference is JetSimpleNameReference) {
|
||||
val pointer = smartPointerManager.createSmartPsiElementPointer(reference.getElement(), file)
|
||||
bindingRequests.add(BindingRequest(pointer, fqName))
|
||||
}
|
||||
else {
|
||||
//TODO: try to shorten reference after (sometimes is possible), need shorten reference to support all relevant cases
|
||||
lengthenReference(referenceExpression, fqName)
|
||||
|
||||
if (refData.kind == KotlinReferenceData.Kind.NON_EXTENSION_CALLABLE || refData.kind == KotlinReferenceData.Kind.EXTENSION_CALLABLE) {
|
||||
descriptorsToImport.addIfNotNull(findCallableToImport(fqName, file))
|
||||
}
|
||||
}
|
||||
|
||||
for (descriptor in descriptorsToImport) {
|
||||
importHelper.importDescriptor(file, descriptor)
|
||||
}
|
||||
for ((pointer, fqName) in bindingRequests) {
|
||||
val reference = pointer.getElement().getReference() as JetSimpleNameReference
|
||||
reference.bindToFqName(fqName, JetSimpleNameReference.ShorteningMode.DELAYED_SHORTENING)
|
||||
}
|
||||
performDelayedShortening(file.getProject())
|
||||
}
|
||||
|
||||
private fun findCallableToImport(fqName: FqName, file: JetFile): CallableDescriptor? {
|
||||
val importDirective = JetPsiFactory(file.getProject()).createImportDirective(ImportPath(fqName, false))
|
||||
val moduleDescriptor = file.getResolutionFacade().findModuleDescriptor(file)
|
||||
val scope = JetModuleUtil.getSubpackagesOfRootScope(moduleDescriptor)
|
||||
val descriptors = QualifiedExpressionResolver()
|
||||
.processImportReference(importDirective, scope, scope, null, BindingTraceContext(), LookupMode.EVERYTHING)
|
||||
.filterIsInstance<CallableDescriptor>()
|
||||
return descriptors.singleOrNull()
|
||||
}
|
||||
|
||||
private fun showRestoreReferencesDialog(project: Project, referencesToRestore: List<ReferenceToRestoreData>): Collection<ReferenceToRestoreData> {
|
||||
@@ -285,45 +289,16 @@ public class KotlinCopyPasteReferenceProcessor() : CopyPastePostProcessor<Refere
|
||||
if (!shouldShowDialog || referencesToRestore.isEmpty()) {
|
||||
return referencesToRestore
|
||||
}
|
||||
val fqNames = referencesToRestore. map { it.fqName.asString() }.toSortedSet()
|
||||
|
||||
val fqNames = referencesToRestore.map { it.refData.fqName }.toSortedSet()
|
||||
|
||||
val dialog = RestoreReferencesDialog(project, fqNames.copyToArray())
|
||||
dialog.show()
|
||||
|
||||
val selectedFqNames = dialog.getSelectedElements()!!.toSet()
|
||||
return referencesToRestore.filter { ref -> selectedFqNames.contains(ref.fqName.asString()) }
|
||||
return referencesToRestore.filter { selectedFqNames.contains(it.refData.fqName) }
|
||||
}
|
||||
|
||||
private fun createQualifiedExpression(psiFactory: JetPsiFactory, text: String)
|
||||
= psiFactory.createExpression(text) as JetDotQualifiedExpression
|
||||
|
||||
private fun lengthenReference(expression: JetElement, fqName: FqName) {
|
||||
assert(canLengthenReferenceExpression(expression, fqName))
|
||||
val parent = expression.getParent()
|
||||
val prefixToInsert = IdeDescriptorRenderers.SOURCE_CODE.renderFqName(fqName.parent())
|
||||
val psiFactory = JetPsiFactory(expression)
|
||||
if (parent is JetCallExpression) {
|
||||
val text = prefixToInsert + "." + parent.getText()
|
||||
parent.replace(createQualifiedExpression(psiFactory, text))
|
||||
}
|
||||
else if (parent is JetUserType) {
|
||||
val typeReference = expression.getStrictParentOfType<JetTypeReference>()!!
|
||||
typeReference.replace(psiFactory.createType(prefixToInsert + "." + typeReference.getText()))
|
||||
}
|
||||
else {
|
||||
expression.replace(createQualifiedExpression(psiFactory, IdeDescriptorRenderers.SOURCE_CODE.renderFqName(fqName)))
|
||||
}
|
||||
}
|
||||
|
||||
private fun canLengthenReferenceExpression(expression: JetElement, fqName: FqName): Boolean {
|
||||
return when {
|
||||
fqName.pathSegments().size() < 2 -> false
|
||||
expression is JetSimpleNameExpression && expression.getReceiverExpression() == null -> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
private val ReferenceData.fqName: FqName
|
||||
get() = FqName(qClassName!!)
|
||||
|
||||
private fun toTextRanges(startOffsets: IntArray, endOffsets: IntArray): List<TextRange> {
|
||||
assert(startOffsets.size() == endOffsets.size())
|
||||
return startOffsets.indices.map { TextRange(startOffsets[it], endOffsets[it]) }
|
||||
@@ -331,6 +306,6 @@ public class KotlinCopyPasteReferenceProcessor() : CopyPastePostProcessor<Refere
|
||||
|
||||
private fun PsiElement.isInCopiedArea(fileCopiedFrom: JetFile, startOffsets: IntArray, endOffsets: IntArray): Boolean {
|
||||
if (getContainingFile() != fileCopiedFrom) return false
|
||||
return toTextRanges(startOffsets, endOffsets).contains(range)
|
||||
return toTextRanges(startOffsets, endOffsets).any { this.range in it }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.idea.codeInsight
|
||||
|
||||
import com.intellij.codeInsight.editorActions.*
|
||||
import java.io.*
|
||||
import java.awt.datatransfer.*
|
||||
import kotlin.properties.*
|
||||
|
||||
public class KotlinReferenceTransferableData(
|
||||
val data: Array<KotlinReferenceData>
|
||||
) : TextBlockTransferableData, Cloneable, Serializable {
|
||||
|
||||
override fun getFlavor() = KotlinReferenceData.dataFlavor
|
||||
|
||||
override fun getOffsetCount() = data.size() * 2
|
||||
|
||||
override fun getOffsets(offsets: IntArray, index: Int): Int {
|
||||
var i = index
|
||||
for (d in data) {
|
||||
offsets[i++] = d.startOffset
|
||||
offsets[i++] = d.endOffset
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
override fun setOffsets(offsets: IntArray, index: Int): Int {
|
||||
var i = index
|
||||
for (d in data) {
|
||||
d.startOffset = offsets[i++]
|
||||
d.endOffset = offsets[i++]
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
public override fun clone() = KotlinReferenceTransferableData(Array(data.size(), { data[it].clone() }))
|
||||
}
|
||||
|
||||
public class KotlinReferenceData(
|
||||
public var startOffset: Int,
|
||||
public var endOffset: Int,
|
||||
public val fqName: String,
|
||||
public val kind: KotlinReferenceData.Kind
|
||||
) : Cloneable, Serializable {
|
||||
|
||||
public enum class Kind {
|
||||
CLASS
|
||||
PACKAGE
|
||||
NON_EXTENSION_CALLABLE
|
||||
EXTENSION_CALLABLE
|
||||
}
|
||||
|
||||
public override fun clone(): KotlinReferenceData {
|
||||
try {
|
||||
return super<Cloneable>.clone() as KotlinReferenceData
|
||||
}
|
||||
catch (e: CloneNotSupportedException) {
|
||||
throw RuntimeException()
|
||||
}
|
||||
}
|
||||
|
||||
class object {
|
||||
public val dataFlavor: DataFlavor? by Delegates.lazy {
|
||||
try {
|
||||
DataFlavor(DataFlavor.javaJVMLocalObjectMimeType + ";class=" + javaClass<KotlinReferenceData>().getName(), "KotlinReferenceData")
|
||||
}
|
||||
catch (e: NoClassDefFoundError) {
|
||||
null
|
||||
}
|
||||
catch (e: IllegalArgumentException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-8
@@ -20,9 +20,8 @@ import com.intellij.refactoring.RefactoringHelper
|
||||
import com.intellij.usageView.UsageInfo
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import org.jetbrains.kotlin.idea.codeInsight.shorten.prepareElementsToShorten
|
||||
import org.jetbrains.kotlin.idea.codeInsight.shorten.withElementsToShorten
|
||||
import org.jetbrains.kotlin.idea.util.ShortenReferences
|
||||
import org.jetbrains.kotlin.idea.codeInsight.shorten.*
|
||||
|
||||
public class KotlinShortenReferencesRefactoringHelper: RefactoringHelper<Any> {
|
||||
override fun prepareOperation(usages: Array<out UsageInfo>?): Any? {
|
||||
@@ -35,12 +34,7 @@ public class KotlinShortenReferencesRefactoringHelper: RefactoringHelper<Any> {
|
||||
|
||||
override fun performOperation(project: Project, operationData: Any?) {
|
||||
ApplicationManager.getApplication()!!.runWriteAction {
|
||||
withElementsToShorten(project) { requests ->
|
||||
val elements = requests.map { it.pointer.getElement() }
|
||||
val options = requests.map { it.options }
|
||||
val elementToOptions = (elements zip options).toMap()
|
||||
ShortenReferences({ elementToOptions[it] ?: ShortenReferences.Options.DEFAULT }).process(elements.filterNotNull())
|
||||
}
|
||||
performDelayedShortening(project)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,14 @@
|
||||
package to
|
||||
|
||||
import a.*
|
||||
import a.E.ENTRY
|
||||
import a.Outer.Inner
|
||||
import a.Outer.Nested
|
||||
import a.Outer.NestedEnum
|
||||
import a.Outer.NestedObj
|
||||
import a.Outer.NestedTrait
|
||||
import a.Outer.NestedAnnotation
|
||||
|
||||
fun f(a: A, t: T) {
|
||||
fun f(p: A, t: T) {
|
||||
g(A(c).ext())
|
||||
O1.f()
|
||||
O2
|
||||
ENTRY
|
||||
E.ENTRY
|
||||
}
|
||||
|
||||
fun f2(i: Inner, n: Nested, e: NestedEnum, o: NestedObj, t: NestedTrait, a: NestedAnnotation) {
|
||||
fun f2(i: Outer.Inner, n: Outer.Nested, e: Outer.NestedEnum, o: Outer.NestedObj, t: Outer.NestedTrait, a: Outer.NestedAnnotation) {
|
||||
ClassObject
|
||||
}
|
||||
@@ -44,7 +44,7 @@ class ClassObject {
|
||||
}
|
||||
}
|
||||
|
||||
<selection>fun f(a: A, t: T) {
|
||||
<selection>fun f(p: A, t: T) {
|
||||
g(A(c).ext())
|
||||
O1.f()
|
||||
O2
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
package to
|
||||
|
||||
import a.Outer.Inner
|
||||
import a.Outer.Nested
|
||||
import a.Outer.NestedEnum
|
||||
import a.Outer.NestedObj
|
||||
import a.Outer.NestedTrait
|
||||
import a.Outer.NestedAnnotation
|
||||
import a.Outer
|
||||
|
||||
fun f(i: Inner, n: Nested, e: NestedEnum, o: NestedObj, t: NestedTrait, a: NestedAnnotation) {
|
||||
fun f(i: Outer.Inner, n: Outer.Nested, e: Outer.NestedEnum, o: Outer.NestedObj, t: Outer.NestedTrait, a: Outer.NestedAnnotation) {
|
||||
}
|
||||
@@ -3,6 +3,6 @@ package to
|
||||
import a.a
|
||||
|
||||
fun f(i: a) {
|
||||
a.a
|
||||
a
|
||||
a()
|
||||
}
|
||||
@@ -3,5 +3,7 @@ package to
|
||||
class A<T> {
|
||||
}
|
||||
|
||||
val a: A<String>? = null
|
||||
|
||||
fun f(b: a.A<Int>) {
|
||||
}
|
||||
@@ -3,4 +3,6 @@ package to
|
||||
class A<T> {
|
||||
}
|
||||
|
||||
val a: A<String>? = null
|
||||
|
||||
<caret>
|
||||
@@ -3,5 +3,7 @@ package to
|
||||
class A() {
|
||||
}
|
||||
|
||||
val a: A? = null
|
||||
|
||||
fun f(a: a.A) {
|
||||
}
|
||||
@@ -3,4 +3,6 @@ package to
|
||||
class A() {
|
||||
}
|
||||
|
||||
val a: A? = null
|
||||
|
||||
<caret>
|
||||
@@ -1,20 +1,14 @@
|
||||
package to
|
||||
|
||||
import a.Outer.Nested.NN
|
||||
import a.Outer.Nested.NI
|
||||
import a.Outer.Inner.IN
|
||||
import a.Outer.Inner.II
|
||||
import a.Outer.Nested.NN2
|
||||
import a.with
|
||||
import a.Outer
|
||||
import a.Outer.Inner.IN2
|
||||
|
||||
fun f(p1: NN, p2: NI, p3: IN, p4: II) {
|
||||
NN2()
|
||||
fun f(p1: Outer.Nested.NN, p2: Outer.Nested.NI, p3: Outer.Inner.IN, p4: Outer.Inner.II) {
|
||||
Outer.Nested.NN2()
|
||||
with(Outer.Nested()) {
|
||||
NI2()
|
||||
}
|
||||
IN2()
|
||||
Outer.Inner.IN2()
|
||||
with(Outer().Inner()) {
|
||||
II2()
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package to
|
||||
|
||||
import a.A
|
||||
import a.get
|
||||
import a.set
|
||||
import a.A
|
||||
|
||||
class B {
|
||||
var a by A()
|
||||
var v by A()
|
||||
}
|
||||
@@ -12,5 +12,5 @@ fun T.set(thisRef: B, desc: PropertyMetadata, value: Int) {
|
||||
class A(): T
|
||||
|
||||
<selection>class B {
|
||||
var a by A()
|
||||
var v by A()
|
||||
}</selection>
|
||||
@@ -11,6 +11,6 @@ public class JavaClass {
|
||||
public class InnerClass {
|
||||
}
|
||||
|
||||
public class NestedClass {
|
||||
public static class NestedClass {
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,10 @@
|
||||
package to
|
||||
|
||||
import java.JavaClass
|
||||
import java.JavaClass.staticMethod
|
||||
import java.JavaClass.NestedClass
|
||||
|
||||
fun f(c: JavaClass) {
|
||||
staticMethod()
|
||||
JavaClass.staticMethod()
|
||||
c.method()
|
||||
c.InnerClass()
|
||||
NestedClass()
|
||||
JavaClass.NestedClass()
|
||||
}
|
||||
@@ -1,28 +1,23 @@
|
||||
package to
|
||||
|
||||
import d.A
|
||||
import d.T
|
||||
import d.g
|
||||
import d.c
|
||||
import d.ext
|
||||
import d.A
|
||||
import d.T
|
||||
import d.Outer
|
||||
import d.O1
|
||||
import d.O2
|
||||
import d.E.ENTRY
|
||||
import d.Outer.Inner
|
||||
import d.Outer.Nested
|
||||
import d.Outer.NestedEnum
|
||||
import d.Outer.NestedObj
|
||||
import d.Outer.NestedTrait
|
||||
import d.Outer.NestedAnnotation
|
||||
import d.E
|
||||
import d.ClassObject
|
||||
|
||||
fun f(a: A, t: T) {
|
||||
g(A(c).ext())
|
||||
O1.f()
|
||||
O2
|
||||
ENTRY
|
||||
E.ENTRY
|
||||
}
|
||||
|
||||
fun f2(i: Inner, n: Nested, e: NestedEnum, o: NestedObj, t: NestedTrait, a: NestedAnnotation) {
|
||||
fun f2(i: Outer.Inner, n: Outer.Nested, e: Outer.NestedEnum, o: Outer.NestedObj, t: Outer.NestedTrait, a: Outer.NestedAnnotation) {
|
||||
ClassObject
|
||||
}
|
||||
@@ -1,11 +1,9 @@
|
||||
package to
|
||||
|
||||
import a.A.A
|
||||
import a.A.B
|
||||
import a.A.C
|
||||
import a.A
|
||||
|
||||
fun f() {
|
||||
A
|
||||
B
|
||||
C
|
||||
A.A
|
||||
A.B
|
||||
A.C
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
package to
|
||||
|
||||
import a.A
|
||||
import a.plus
|
||||
import a.infix
|
||||
import a.A
|
||||
|
||||
fun f(a: A) {
|
||||
a + a
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package to
|
||||
|
||||
import a.A
|
||||
import a.ext
|
||||
import a.p
|
||||
|
||||
fun A.ext() {
|
||||
}
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
package to
|
||||
|
||||
import a.A
|
||||
import a.ext
|
||||
import a.plus
|
||||
import a.infix
|
||||
import a.minus
|
||||
import a.p
|
||||
|
||||
fun A.ext() {
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package to
|
||||
|
||||
import a.A
|
||||
import a.iterator
|
||||
import a.next
|
||||
import a.hasNext
|
||||
import a.A
|
||||
|
||||
fun f() {
|
||||
for (i in A()) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package to
|
||||
|
||||
import a.A
|
||||
import a.get
|
||||
import a.A
|
||||
|
||||
fun f() {
|
||||
A()[""]
|
||||
|
||||
@@ -1,28 +1,23 @@
|
||||
package to
|
||||
|
||||
import d.A
|
||||
import d.T
|
||||
import d.g
|
||||
import d.c
|
||||
import d.ext
|
||||
import d.A
|
||||
import d.T
|
||||
import d.Outer
|
||||
import d.O1
|
||||
import d.O2
|
||||
import d.E.ENTRY
|
||||
import d.Outer.Inner
|
||||
import d.Outer.Nested
|
||||
import d.Outer.NestedEnum
|
||||
import d.Outer.NestedObj
|
||||
import d.Outer.NestedTrait
|
||||
import d.Outer.NestedAnnotation
|
||||
import d.E
|
||||
import d.ClassObject
|
||||
|
||||
fun f(a: A, t: T) {
|
||||
g(A(c).ext())
|
||||
O1.f()
|
||||
O2
|
||||
ENTRY
|
||||
E.ENTRY
|
||||
}
|
||||
|
||||
fun f2(i: Inner, n: Nested, e: NestedEnum, o: NestedObj, t: NestedTrait, a: NestedAnnotation) {
|
||||
fun f2(i: Outer.Inner, n: Outer.Nested, e: Outer.NestedEnum, o: Outer.NestedObj, t: Outer.NestedTrait, a: Outer.NestedAnnotation) {
|
||||
ClassObject
|
||||
}
|
||||
@@ -1,13 +1,7 @@
|
||||
package to
|
||||
|
||||
import a.Outer.Inner
|
||||
import a.Outer.Nested
|
||||
import a.Outer.NestedEnum
|
||||
import a.Outer.NestedObj
|
||||
import a.Outer.NestedTrait
|
||||
import a.Outer.NestedAnnotation
|
||||
import a.Outer
|
||||
|
||||
fun f(i: Inner, n: Nested, e: NestedEnum, o: NestedObj, t: NestedTrait, a: NestedAnnotation) {
|
||||
fun f(i: Outer.Inner, n: Outer.Nested, e: Outer.NestedEnum, o: Outer.NestedObj, t: Outer.NestedTrait, aa: Outer.NestedAnnotation) {
|
||||
Outer().Inner2()
|
||||
}
|
||||
@@ -18,6 +18,6 @@ class Outer {
|
||||
annotation class NestedAnnotation
|
||||
}
|
||||
|
||||
<selection>fun f(i: Inner, n: Nested, e: NestedEnum, o: NestedObj, t: NestedTrait, a: NestedAnnotation) {
|
||||
<selection>fun f(i: Inner, n: Nested, e: NestedEnum, o: NestedObj, t: NestedTrait, aa: NestedAnnotation) {
|
||||
Outer().Inner2()
|
||||
}</selection>
|
||||
@@ -1,7 +1,7 @@
|
||||
package to
|
||||
|
||||
import a.A
|
||||
import a.invoke
|
||||
import a.A
|
||||
|
||||
fun f(a: A) {
|
||||
a()
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package to
|
||||
|
||||
import a.A
|
||||
import a.component1
|
||||
import a.component2
|
||||
import a.A
|
||||
|
||||
fun f() {
|
||||
val (a, b) = A()
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package to
|
||||
|
||||
import a.A
|
||||
import a.B
|
||||
import a.next
|
||||
import a.hasNext
|
||||
import a.A
|
||||
import a.B
|
||||
|
||||
fun A.iterator() = B()
|
||||
|
||||
|
||||
@@ -1,20 +1,12 @@
|
||||
package a
|
||||
|
||||
import a.E.ENTRY
|
||||
import a.Outer.Inner
|
||||
import a.Outer.Nested
|
||||
import a.Outer.NestedEnum
|
||||
import a.Outer.NestedObj
|
||||
import a.Outer.NestedTrait
|
||||
import a.Outer.NestedAnnotation
|
||||
|
||||
fun f(a: A, t: T) {
|
||||
fun f(p: A, t: T) {
|
||||
g(A(c).ext())
|
||||
O1.f()
|
||||
O2
|
||||
ENTRY
|
||||
E.ENTRY
|
||||
}
|
||||
|
||||
fun f2(i: Inner, n: Nested, e: NestedEnum, o: NestedObj, t: NestedTrait, a: NestedAnnotation) {
|
||||
fun f2(i: Outer.Inner, n: Outer.Nested, e: Outer.NestedEnum, o: Outer.NestedObj, t: Outer.NestedTrait, a: Outer.NestedAnnotation) {
|
||||
ClassObject
|
||||
}
|
||||
@@ -44,7 +44,7 @@ class ClassObject {
|
||||
}
|
||||
}
|
||||
|
||||
<selection>fun f(a: A, t: T) {
|
||||
<selection>fun f(p: A, t: T) {
|
||||
g(A(c).ext())
|
||||
O1.f()
|
||||
O2
|
||||
|
||||
@@ -5,5 +5,7 @@ class A {
|
||||
}
|
||||
}
|
||||
|
||||
val v: A? = null
|
||||
|
||||
fun f(p: a.A.B) {
|
||||
}
|
||||
@@ -5,4 +5,6 @@ class A {
|
||||
}
|
||||
}
|
||||
|
||||
val v: A? = null
|
||||
|
||||
<caret>
|
||||
@@ -1,6 +1,6 @@
|
||||
package to
|
||||
|
||||
import a.T
|
||||
import a.A
|
||||
import a.T
|
||||
|
||||
fun f(): T<A>
|
||||
Reference in New Issue
Block a user