Compare commits

...

16 Commits

Author SHA1 Message Date
Alexey Sedunov
16f6bf4fa6 Analyze Data Flow: Add usage context panels 2017-06-05 16:36:21 +03:00
Alexey Sedunov
33bddb42c0 Analyze Data Flow: Respect member hierarchies
#KT-11994 In Progress
2017-06-05 16:36:14 +03:00
Alexey Sedunov
64c1d8e1ce Analyze Data Flow: Support val/var parameters
#KT-11994 In Progress
2017-06-05 16:36:08 +03:00
Alexey Sedunov
4406a4bec8 Analyze Data Flow: Support properties with custom accessors
#KT-11994 In Progress
2017-06-05 16:36:01 +03:00
Alexey Sedunov
f33f7d6c75 Analyze Data Flow: Support callable references
#KT-11994 In Progress
2017-06-05 16:35:54 +03:00
Alexey Sedunov
84be3c1ba3 Analyze Data Flow: Support lambdas/anonymous functions
#KT-11994 In Progress
2017-06-05 16:35:48 +03:00
Alexey Sedunov
49640b38f5 Analyze Data Flow: Support dereference processing
#KT-11994 In Progress
2017-06-05 16:35:41 +03:00
Alexey Sedunov
823ccee42a Analyze Data Flow: Initial implementation
#KT-11994 In Progress
2017-06-05 16:35:34 +03:00
Alexey Sedunov
605084e151 Copy: Enable file copy for mixed Java-Kotlin case
Also merge CopyKotlinFileHandler with CopyKotlinDeclarationsHandler
as it currently can't be invoked for such cases

 #KT-18200 Fixed
2017-06-05 16:26:10 +03:00
Alexey Sedunov
f3bcac16e8 Copy/Move: Fix processing of imported Java static members
#KT-18098 Fixed
2017-06-05 13:04:33 +03:00
Alexey Sedunov
cd376c20fb Rename: Fix rename of import alias referring to object member
#KT-18096 Fixed
2017-06-05 13:04:26 +03:00
Alexey Sedunov
f8c3e42124 Rename: Disable member inplace when variable inplace is available 2017-06-05 13:04:19 +03:00
Alexey Sedunov
a36dddba04 Rename: Disable label rename outside of reference range
#KT-17128 Fixed
2017-06-05 13:04:12 +03:00
Alexey Sedunov
2d96e9366a Rename: Disable Java member rename by reference to import alias
#KT-18076 Fixed
2017-06-05 13:04:03 +03:00
Alexey Sedunov
5f6c9714d6 Rename: Fix inplace refactoring for declarations with backticked names
#KT-15859 Fixed
2017-06-05 13:03:56 +03:00
Alexey Sedunov
74f404fc76 Copy: Rename only self-usages of the copied class
#KT-18034 Fixed
2017-06-05 13:03:49 +03:00
250 changed files with 3580 additions and 89 deletions

View File

@@ -248,13 +248,13 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
override fun returnValue(returnExpression: KtExpression, returnValue: PseudoValue, subroutine: KtElement) {
val exitPoint = getSubroutineExitPoint(subroutine) ?: return
handleJumpInsideTryFinally(exitPoint)
add(ReturnValueInstruction(returnExpression, currentScope, exitPoint, returnValue))
add(ReturnValueInstruction(returnExpression, currentScope, exitPoint, returnValue, subroutine))
}
override fun returnNoValue(returnExpression: KtReturnExpression, subroutine: KtElement) {
val exitPoint = getSubroutineExitPoint(subroutine) ?: return
handleJumpInsideTryFinally(exitPoint)
add(ReturnNoValueInstruction(returnExpression, currentScope, exitPoint))
add(ReturnNoValueInstruction(returnExpression, currentScope, exitPoint, subroutine))
}
override fun write(

View File

@@ -19,6 +19,8 @@ package org.jetbrains.kotlin.cfg.pseudocode.instructions.eval
import org.jetbrains.kotlin.cfg.pseudocode.PseudoValue
import org.jetbrains.kotlin.cfg.pseudocode.PseudoValueFactory
import org.jetbrains.kotlin.cfg.pseudocode.instructions.*
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtNamedDeclaration
@@ -39,6 +41,13 @@ sealed class AccessTarget {
object BlackBox: AccessTarget()
}
val AccessTarget.accessedDescriptor: CallableDescriptor?
get() = when (this) {
is AccessTarget.Declaration -> descriptor
is AccessTarget.Call -> resolvedCall.resultingDescriptor
is AccessTarget.BlackBox -> null
}
abstract class AccessValueInstruction protected constructor(
element: KtElement,
blockScope: BlockScope,

View File

@@ -25,7 +25,8 @@ import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionVisitorWithRe
class ReturnNoValueInstruction(
element: KtElement,
blockScope: BlockScope,
targetLabel: Label
targetLabel: Label,
val subroutine: KtElement
) : AbstractJumpInstruction(element, targetLabel, blockScope) {
override fun accept(visitor: InstructionVisitor) {
visitor.visitReturnNoValue(this)
@@ -38,5 +39,5 @@ class ReturnNoValueInstruction(
override fun toString(): String = "ret $targetLabel"
override fun createCopy(newLabel: Label, blockScope: BlockScope): AbstractJumpInstruction =
ReturnNoValueInstruction(element, blockScope, newLabel)
ReturnNoValueInstruction(element, blockScope, newLabel, subroutine)
}

View File

@@ -23,13 +23,15 @@ import java.util.Collections
import org.jetbrains.kotlin.cfg.pseudocode.instructions.BlockScope
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionVisitor
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionVisitorWithResult
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtReturnExpression
class ReturnValueInstruction(
returnExpression: KtExpression,
blockScope: BlockScope,
targetLabel: Label,
val returnedValue: PseudoValue
val returnedValue: PseudoValue,
val subroutine: KtElement
) : AbstractJumpInstruction(returnExpression, targetLabel, blockScope) {
override val inputValues: List<PseudoValue> get() = Collections.singletonList(returnedValue)
@@ -46,7 +48,7 @@ class ReturnValueInstruction(
}
override fun createCopy(newLabel: Label, blockScope: BlockScope): AbstractJumpInstruction {
return ReturnValueInstruction((element as KtExpression), blockScope, newLabel, returnedValue)
return ReturnValueInstruction((element as KtExpression), blockScope, newLabel, returnedValue, subroutine)
}
val returnExpressionIfAny: KtReturnExpression? = element as? KtReturnExpression

View File

@@ -183,7 +183,7 @@ public class KtParameter extends KtNamedDeclarationStub<KotlinParameterStub> imp
}
@Nullable
public KtFunction getOwnerFunction() {
public KtDeclarationWithBody getOwnerFunction() {
PsiElement parent = getParentByStub();
if (!(parent instanceof KtParameterList)) return null;
return ((KtParameterList) parent).getOwnerFunction();

View File

@@ -74,10 +74,10 @@ public class KtParameterList extends KtElementImplStub<KotlinPlaceHolderStub<KtP
removeParameter(getParameters().get(index));
}
public KtFunction getOwnerFunction() {
public KtDeclarationWithBody getOwnerFunction() {
PsiElement parent = getParentByStub();
if (!(parent instanceof KtFunction)) return null;
return (KtFunction) parent;
if (!(parent instanceof KtDeclarationWithBody)) return null;
return (KtDeclarationWithBody) parent;
}
@Nullable

View File

@@ -130,6 +130,7 @@ import org.jetbrains.kotlin.idea.repl.AbstractIdeReplCompletionTest
import org.jetbrains.kotlin.idea.resolve.*
import org.jetbrains.kotlin.idea.script.AbstractScriptConfigurationHighlightingTest
import org.jetbrains.kotlin.idea.script.AbstractScriptConfigurationNavigationTest
import org.jetbrains.kotlin.idea.slicer.AbstractSlicerTest
import org.jetbrains.kotlin.idea.structureView.AbstractKotlinFileStructureTest
import org.jetbrains.kotlin.idea.stubs.AbstractMultiFileHighlightingTest
import org.jetbrains.kotlin.idea.stubs.AbstractResolveByStubTest
@@ -1022,6 +1023,10 @@ fun main(args: Array<String>) {
testClass<AbstractNameSuggestionProviderTest> {
model("refactoring/nameSuggestionProvider")
}
testClass<AbstractSlicerTest> {
model("slicer", singleClass = true)
}
}
testGroup("idea/idea-maven/test", "idea/idea-maven/testData") {

View File

@@ -45,6 +45,7 @@ import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElementSelector
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DataClassDescriptorResolver
import org.jetbrains.kotlin.resolve.ImportedFromObjectCallableDescriptor
import org.jetbrains.kotlin.resolve.descriptorUtil.getImportableDescriptor
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.types.expressions.OperatorConventions
@@ -241,13 +242,15 @@ class KtSimpleNameReference(expression: KtSimpleNameExpression) : KtSimpleRefere
}
fun getImportAlias(): KtImportAlias? {
fun DeclarationDescriptor.unwrap() = if (this is ImportedFromObjectCallableDescriptor<*>) callableFromObject else this
val element = element
val name = element.getReferencedName()
val file = element.containingKtFile
val importDirective = file.findImportByAlias(name) ?: return null
val fqName = importDirective.importedFqName ?: return null
val importedDescriptors = file.resolveImportReference(fqName)
if (getTargetDescriptors(element.analyze(BodyResolveMode.PARTIAL)).any { it.getImportableDescriptor() in importedDescriptors }) {
val importedDescriptors = file.resolveImportReference(fqName).map { it.unwrap() }
if (getTargetDescriptors(element.analyze(BodyResolveMode.PARTIAL)).any { it.unwrap().getImportableDescriptor() in importedDescriptors }) {
return importDirective.alias
}
return null

View File

@@ -28,6 +28,10 @@ import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
class KotlinReadWriteAccessDetector : ReadWriteAccessDetector() {
companion object {
val INSTANCE = KotlinReadWriteAccessDetector()
}
override fun isReadWriteAccessible(element: PsiElement) = element is KtVariableDeclaration || element is KtParameter
override fun isDeclarationWriteAccess(element: PsiElement) = isReadWriteAccessible(element)

View File

@@ -155,7 +155,7 @@ class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, ReferencesSearc
private fun searchNamedArguments(parameter: KtParameter) {
val parameterName = parameter.name ?: return
val function = parameter.ownerFunction ?: return
val function = parameter.ownerFunction as? KtFunction ?: return
if (function.nameAsName?.isSpecial ?: true) return
val project = function.project
var namedArgsScope = function.useScope.intersectWith(queryParameters.scopeDeterminedByUser)

View File

@@ -410,10 +410,6 @@
id="kotlinClass"
implementation="org.jetbrains.kotlin.idea.refactoring.copy.CopyKotlinDeclarationsHandler"
order="first" />
<refactoring.copyHandler
id="kotlinFile"
implementation="org.jetbrains.kotlin.idea.refactoring.copy.CopyKotlinFileHandler"
order="after kotlinClass" />
<refactoring.changeSignatureUsageProcessor
implementation="org.jetbrains.kotlin.idea.refactoring.changeSignature.KotlinChangeSignatureUsageProcessor"
order="after javaProcessor" />
@@ -516,6 +512,7 @@
<renameHandler implementation="org.jetbrains.kotlin.idea.refactoring.rename.RenameClassByCompanionObjectShortReferenceHandler"/>
<renameHandler implementation="org.jetbrains.kotlin.idea.refactoring.rename.RenameByLabeledReferenceInLambdaArgumentHandler"/>
<renameHandler implementation="org.jetbrains.kotlin.idea.refactoring.rename.RenameImportAliasByReferenceHandler"/>
<renameHandler implementation="org.jetbrains.kotlin.idea.refactoring.rename.KotlinMemberInplaceRenameHandler"/>
<automaticRenamerFactory implementation="org.jetbrains.kotlin.idea.refactoring.rename.AutomaticVariableRenamerFactory"/>
<automaticRenamerFactory implementation="org.jetbrains.kotlin.idea.refactoring.rename.AutomaticVariableRenamerFactoryForJavaClass"/>
<automaticRenamerFactory implementation="org.jetbrains.kotlin.idea.refactoring.rename.AutomaticVariableInJavaRenamerFactory"/>
@@ -813,6 +810,11 @@
<facetType implementation="org.jetbrains.kotlin.idea.facet.KotlinFacetType"/>
<lang.sliceProvider language="kotlin" implementationClass="org.jetbrains.kotlin.idea.slicer.KotlinSliceProvider"/>
<usageContextPanelProvider implementation="org.jetbrains.kotlin.idea.slicer.KotlinUsageContextDataInflowPanel$Provider"/>
<usageContextPanelProvider implementation="org.jetbrains.kotlin.idea.slicer.KotlinUsageContextDataOutflowPanel$Provider"/>
<intentionAction>
<className>org.jetbrains.kotlin.idea.intentions.FoldInitializerAndIfToElvisIntention</className>
<category>Kotlin</category>

View File

@@ -64,7 +64,7 @@ class KotlinFindUsagesHandlerFactory(project: Project) : FindUsagesHandlerFactor
return createFindUsagesHandler(element, forHighlightUsages, canAsk = !forHighlightUsages)
}
private fun createFindUsagesHandler(element: PsiElement, forHighlightUsages: Boolean, canAsk: Boolean): FindUsagesHandler {
fun createFindUsagesHandler(element: PsiElement, forHighlightUsages: Boolean, canAsk: Boolean): FindUsagesHandler {
val handler = createFindUsagesHandlerNoDecoration(element, canAsk)
return Extensions.getArea(element.project).getExtensionPoint(KotlinFindUsagesHandlerDecorator.EP_NAME).extensions.fold(handler) {
@@ -124,7 +124,7 @@ class KotlinFindUsagesHandlerFactory(project: Project) : FindUsagesHandlerFactor
}
}
private fun handlerForMultiple(originalDeclaration: KtNamedDeclaration, declarations: Collection<PsiElement>): FindUsagesHandler {
fun handlerForMultiple(originalDeclaration: KtNamedDeclaration, declarations: Collection<PsiElement>): FindUsagesHandler {
return when (declarations.size) {
0 -> FindUsagesHandler.NULL_HANDLER

View File

@@ -0,0 +1,38 @@
/*
* Copyright 2010-2017 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.findUsages
import com.intellij.find.findUsages.FindUsagesOptions
import com.intellij.usageView.UsageInfo
import org.jetbrains.kotlin.psi.KtDeclaration
fun KtDeclaration.processAllExactUsages(
options: () -> FindUsagesOptions,
processor: (UsageInfo) -> Unit
) {
val findUsagesHandler = KotlinFindUsagesHandlerFactory(project).createFindUsagesHandler(this, false, false)
findUsagesHandler.processElementUsages(
this,
{
if (it.reference?.isReferenceTo(this) ?: false) {
processor(it)
}
true
},
options()
)
}

View File

@@ -65,6 +65,7 @@ class KotlinFunctionFindUsagesOptions(project: Project): KotlinCallableFindUsage
}
class KotlinPropertyFindUsagesOptions(project: Project): KotlinCallableFindUsagesOptions, JavaVariableFindUsagesOptions(project) {
var isReadWriteAccess: Boolean = true
override var searchOverrides: Boolean = false
override fun toJavaOptions(project: Project): JavaVariableFindUsagesOptions {

View File

@@ -112,7 +112,7 @@ abstract class KotlinFindMemberUsagesHandler<T : KtNamedDeclaration>
when (access) {
ReadWriteAccessDetector.Access.Read -> kotlinOptions.isReadAccess
ReadWriteAccessDetector.Access.Write -> kotlinOptions.isWriteAccess
ReadWriteAccessDetector.Access.ReadWrite -> true
ReadWriteAccessDetector.Access.ReadWrite -> kotlinOptions.isReadWriteAccess
}
}
}

View File

@@ -327,7 +327,7 @@ class ConvertFunctionTypeParameterToReceiverIntention : SelfTargetingRangeIntent
if (functionType.receiverTypeReference != null) return null
val lambdaType = functionType.getAbbreviatedTypeOrType(functionType.analyze(BodyResolveMode.PARTIAL)) ?: return null
val containingParameter = (functionType.parent as? KtTypeReference)?.parent as? KtParameter ?: return null
val ownerFunction = containingParameter.ownerFunction ?: return null
val ownerFunction = containingParameter.ownerFunction as? KtFunction ?: return null
val typeParameterIndex = functionType.parameters.indexOf(parameter)
val functionParameterIndex = ownerFunction.valueParameters.indexOf(containingParameter)
return ConversionData(typeParameterIndex, functionParameterIndex, lambdaType, ownerFunction)

View File

@@ -195,7 +195,7 @@ class ConvertFunctionTypeReceiverToParameterIntention : SelfTargetingRangeIntent
?.getReceiverTypeFromFunctionType()
?: return null
val containingParameter = (functionType.parent as? KtTypeReference)?.parent as? KtParameter ?: return null
val ownerFunction = containingParameter.ownerFunction ?: return null
val ownerFunction = containingParameter.ownerFunction as? KtFunction ?: return null
val functionParameterIndex = ownerFunction.valueParameters.indexOf(containingParameter)
return ConversionData(functionParameterIndex, lambdaReceiverType, ownerFunction)
}

View File

@@ -99,7 +99,8 @@ class KtParameterPattern : PsiElementPattern<KtParameter, KtParameterPattern>(Kt
override fun processValues(ktParameter: KtParameter,
context: ProcessingContext,
processor: PairProcessor<KtFunction, ProcessingContext>): Boolean {
return processor.process(ktParameter.ownerFunction, context)
val function = ktParameter.ownerFunction as? KtFunction ?: return true
return processor.process(function, context)
}
override fun accepts(ktParameter: KtParameter, context: ProcessingContext): Boolean {

View File

@@ -25,18 +25,20 @@ import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiDirectory
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiFileSystemItem
import com.intellij.psi.search.LocalSearchScope
import com.intellij.psi.search.searches.ReferencesSearch
import com.intellij.refactoring.BaseRefactoringProcessor
import com.intellij.refactoring.RefactoringBundle
import com.intellij.refactoring.copy.CopyFilesOrDirectoriesDialog
import com.intellij.refactoring.copy.CopyFilesOrDirectoriesHandler
import com.intellij.refactoring.copy.CopyHandlerDelegateBase
import com.intellij.refactoring.rename.RenameProcessor
import com.intellij.refactoring.util.MoveRenameUsageInfo
import com.intellij.usageView.UsageInfo
import com.intellij.util.IncorrectOperationException
import com.intellij.util.containers.MultiMap
import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.idea.codeInsight.shorten.performDelayedRefactoringRequests
import org.jetbrains.kotlin.idea.core.quoteIfNeeded
import org.jetbrains.kotlin.idea.refactoring.checkConflictsInteractively
import org.jetbrains.kotlin.idea.refactoring.createKotlinFile
import org.jetbrains.kotlin.idea.refactoring.move.*
@@ -71,7 +73,20 @@ class CopyKotlinDeclarationsHandler : CopyHandlerDelegateBase() {
}
}
override fun canCopy(elements: Array<out PsiElement>, fromUpdate: Boolean): Boolean {
private val copyFilesHandler by lazy { CopyFilesOrDirectoriesHandler() }
private fun getSourceFiles(elements: Array<out PsiElement>): Array<PsiElement>? {
return elements
.map { it.containingFile ?: it as? PsiFileSystemItem ?: return null }
.toTypedArray()
}
private fun canCopyFiles(elements: Array<out PsiElement>, fromUpdate: Boolean): Boolean {
val sourceFiles = getSourceFiles(elements) ?: return false
return copyFilesHandler.canCopy(sourceFiles, fromUpdate)
}
private fun canCopyDeclarations(elements: Array<out PsiElement>): Boolean {
val containingFile =
elements
.flatMap { it.getElementsToCopy().ifEmpty { return false } }
@@ -81,6 +96,10 @@ class CopyKotlinDeclarationsHandler : CopyHandlerDelegateBase() {
return containingFile.sourceRoot != null
}
override fun canCopy(elements: Array<out PsiElement>, fromUpdate: Boolean): Boolean {
return canCopyDeclarations(elements) || canCopyFiles(elements, fromUpdate)
}
enum class ExistingFilePolicy {
APPEND, OVERWRITE, SKIP
}
@@ -149,6 +168,11 @@ class CopyKotlinDeclarationsHandler : CopyHandlerDelegateBase() {
}
override fun doCopy(elements: Array<out PsiElement>, defaultTargetDirectory: PsiDirectory?) {
if (!canCopyDeclarations(elements)) {
val sourceFiles = getSourceFiles(elements) ?: return
return copyFilesHandler.doCopy(sourceFiles, defaultTargetDirectory)
}
val elementsToCopy = elements.flatMap { it.getElementsToCopy() }
if (elementsToCopy.isEmpty()) return
@@ -240,8 +264,13 @@ class CopyKotlinDeclarationsHandler : CopyHandlerDelegateBase() {
performDelayedRefactoringRequests(project)
}
oldToNewElementsMapping.values.singleOrNull()?.let {
RenameProcessor(project, it, newName!!.quoteIfNeeded(), false, false).run()
(oldToNewElementsMapping.values.singleOrNull() as? KtNamedDeclaration)?.let { newDeclaration ->
if (newName == newDeclaration.name) return@let
val selfReferences = ReferencesSearch.search(newDeclaration, LocalSearchScope(newDeclaration)).findAll()
runWriteAction {
selfReferences.forEach { it.handleElementRename(newName!!) }
newDeclaration.setName(newName!!)
}
}
if (openInEditor) {

View File

@@ -1,44 +0,0 @@
/*
* 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.refactoring.copy
import com.intellij.psi.PsiDirectory
import com.intellij.psi.PsiElement
import com.intellij.refactoring.copy.CopyFilesOrDirectoriesHandler
import com.intellij.refactoring.copy.CopyHandlerDelegateBase
import org.jetbrains.kotlin.psi.KtFile
class CopyKotlinFileHandler : CopyHandlerDelegateBase() {
private val delegate = CopyFilesOrDirectoriesHandler()
private fun adjustElements(elements: Array<out PsiElement>): Array<PsiElement>? {
return elements
.map { (if (it.isValid) it.containingFile as? KtFile else null) ?: return null }
.toTypedArray()
}
override fun canCopy(elements: Array<out PsiElement>, fromUpdate: Boolean): Boolean {
return delegate.canCopy(adjustElements(elements) ?: return false, fromUpdate)
}
override fun doCopy(elements: Array<out PsiElement>, defaultTargetDirectory: PsiDirectory?) {
return delegate.doCopy(adjustElements(elements) ?: return, defaultTargetDirectory)
}
override fun doClone(element: PsiElement?) = delegate.doClone(element)
}

View File

@@ -42,6 +42,7 @@ import org.jetbrains.kotlin.idea.refactoring.fqName.isImported
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference.ShorteningMode
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.*
@@ -123,6 +124,17 @@ fun KtElement.processInternalReferencesToUpdateOnPackageNameChange(
val isExtension = isCallable && refExpr.isExtensionRef(bindingContext)
val isCallableReference = isCallableReference(refExpr.mainReference)
val declaration by lazy {
var result = DescriptorToSourceUtilsIde.getAnyDeclaration(project, descriptor) ?: return@lazy null
if (descriptor.isCompanionObject()
&& bindingContext[BindingContext.SHORT_REFERENCE_TO_COMPANION_OBJECT, refExpr] != null) {
result = (result as KtObjectDeclaration).containingClassOrObject ?: result
}
result
}
if (isCallable) {
if (!isCallableReference) {
if (isExtension && containingDescriptor is ClassDescriptor) {
@@ -137,17 +149,11 @@ fun KtElement.processInternalReferencesToUpdateOnPackageNameChange(
if (!isExtension) {
if (!(containingDescriptor is PackageFragmentDescriptor
|| containingDescriptor is ClassDescriptor && containingDescriptor.kind == ClassKind.OBJECT)) return null
|| containingDescriptor is ClassDescriptor && containingDescriptor.kind == ClassKind.OBJECT
|| descriptor is JavaCallableMemberDescriptor && ((declaration as? PsiMember)?.hasModifierProperty(PsiModifier.STATIC) ?: false))) return null
}
}
var declaration = DescriptorToSourceUtilsIde.getAnyDeclaration(project, descriptor) ?: return null
if (descriptor.isCompanionObject()
&& bindingContext[BindingContext.SHORT_REFERENCE_TO_COMPANION_OBJECT, refExpr] != null) {
declaration = (declaration as KtObjectDeclaration).containingClassOrObject ?: declaration
}
if (!DescriptorUtils.getFqName(descriptor).isSafe) return null
val (oldContainer, newContainer) = containerChangeInfo
@@ -166,6 +172,8 @@ fun KtElement.processInternalReferencesToUpdateOnPackageNameChange(
val isImported = isImported(descriptor)
if (isImported && this is KtFile) return null
if (declaration == null) return null
if (isExtension || containerFqName != null || isImported) return {
createMoveUsageInfoIfPossible(it.mainReference, declaration, false, true)
}

View File

@@ -28,21 +28,31 @@ import com.intellij.refactoring.rename.PsiElementRenameHandler
import com.intellij.refactoring.rename.RenameHandler
import com.intellij.refactoring.rename.inplace.MemberInplaceRenameHandler
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
abstract class AbstractReferenceSubstitutionRenameHandler(
private val delegateHandler: RenameHandler = MemberInplaceRenameHandler()
) : PsiElementRenameHandler() {
protected fun getReferenceExpression(dataContext: DataContext): KtSimpleNameExpression? {
val caret = CommonDataKeys.CARET.getData(dataContext) ?: return null
val ktFile = CommonDataKeys.PSI_FILE.getData(dataContext) as? KtFile ?: return null
var elementAtCaret = ktFile.findElementAt(caret.offset)
if (elementAtCaret is PsiWhiteSpace) {
elementAtCaret = CodeInsightUtils.getElementAtOffsetIgnoreWhitespaceAfter(ktFile, caret.offset)
companion object {
fun getReferenceExpression(file: PsiFile, offset: Int): KtSimpleNameExpression? {
var elementAtCaret = file.findElementAt(offset) ?: return null
if (elementAtCaret.node?.elementType == KtTokens.AT) return null
if (elementAtCaret is PsiWhiteSpace) {
elementAtCaret = CodeInsightUtils.getElementAtOffsetIgnoreWhitespaceAfter(file, offset) ?: return null
if (offset != elementAtCaret.endOffset) return null
}
return elementAtCaret.getNonStrictParentOfType<KtSimpleNameExpression>()
}
fun getReferenceExpression(dataContext: DataContext): KtSimpleNameExpression? {
val caret = CommonDataKeys.CARET.getData(dataContext) ?: return null
val ktFile = CommonDataKeys.PSI_FILE.getData(dataContext) as? KtFile ?: return null
return getReferenceExpression(ktFile, caret.offset)
}
return elementAtCaret?.getNonStrictParentOfType<KtSimpleNameExpression>()
}
protected abstract fun getElementToRename(dataContext: DataContext): PsiElement?

View File

@@ -26,6 +26,7 @@ import com.intellij.refactoring.rename.inplace.MemberInplaceRenameHandler
import com.intellij.refactoring.rename.inplace.MemberInplaceRenamer
import org.jetbrains.kotlin.asJava.unwrapped
import org.jetbrains.kotlin.idea.references.SyntheticPropertyAccessorReference
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.psi.KtPsiUtil
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
@@ -46,6 +47,7 @@ class JavaMemberByKotlinReferenceInplaceRenameHandler : MemberInplaceRenameHandl
if (element?.unwrapped !is PsiMember) return false
val refExpr = file.findElementAt(editor.caretModel.offset)?.getNonStrictParentOfType<KtSimpleNameExpression>() ?: return false
if (refExpr.references.any { (it as? SyntheticPropertyAccessorReference)?.resolve() != null }) return false
if (refExpr.mainReference.getImportAlias() != null) return false
return true
}

View File

@@ -0,0 +1,79 @@
/*
* Copyright 2010-2017 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.refactoring.rename
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.util.Comparing
import com.intellij.psi.*
import com.intellij.refactoring.rename.inplace.MemberInplaceRenameHandler
import com.intellij.refactoring.rename.inplace.MemberInplaceRenamer
import com.intellij.refactoring.rename.inplace.VariableInplaceRenameHandler
import com.intellij.refactoring.rename.inplace.VariableInplaceRenamer
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.core.unquote
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtLabelReferenceExpression
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
class KotlinMemberInplaceRenameHandler : MemberInplaceRenameHandler() {
companion object {
private val variableInplaceHandler = object : VariableInplaceRenameHandler() {
override public fun isAvailable(element: PsiElement?, editor: Editor?, file: PsiFile?): Boolean {
return super.isAvailable(element, editor, file)
}
}
}
private class RenamerImpl(
elementToRename: PsiNamedElement,
substitutedElement: PsiElement?,
editor: Editor,
currentName: String,
oldName: String
) : MemberInplaceRenamer(elementToRename, substitutedElement, editor, currentName, oldName) {
override fun acceptReference(reference: PsiReference): Boolean {
val refElement = reference.element
val textRange = reference.rangeInElement
val referenceText = refElement.text.substring(textRange.startOffset, textRange.endOffset).unquote()
return Comparing.strEqual(referenceText, myElementToRename.name)
}
override fun createInplaceRenamerToRestart(variable: PsiNamedElement, editor: Editor, initialName: String): VariableInplaceRenamer {
return RenamerImpl(variable, substituted, editor, initialName, myOldName)
}
}
override fun createMemberRenamer(element: PsiElement, elementToRename: PsiNameIdentifierOwner, editor: Editor): MemberInplaceRenamer {
val currentName = elementToRename.nameIdentifier?.text ?: ""
return RenamerImpl(elementToRename, element, editor, currentName, currentName)
}
override fun isAvailable(element: PsiElement?, editor: Editor, file: PsiFile): Boolean {
if (variableInplaceHandler.isAvailable(element, editor, file)) return false
if (element !is KtElement) return false
if (!super.isAvailable(element, editor, file)) return false
val referenceExpression = AbstractReferenceSubstitutionRenameHandler.getReferenceExpression(file, editor.caretModel.offset) ?: return true
if (referenceExpression is KtLabelReferenceExpression) return false
if (referenceExpression.mainReference.getImportAlias() != null) return false
if (referenceExpression.analyze(BodyResolveMode.PARTIAL)[BindingContext.SHORT_REFERENCE_TO_COMPANION_OBJECT, referenceExpression] != null) return false
return true
}
}

View File

@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.idea.references.KtDestructuringDeclarationReference
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.references.resolveMainReferenceToDescriptors
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
@@ -112,7 +113,10 @@ class KotlinTargetElementEvaluator : TargetElementEvaluatorEx, TargetElementUtil
}
override fun isIdentifierPart(file: PsiFile, text: CharSequence?, offset: Int): Boolean {
val elementAtCaret = file.findElementAt(offset)
if (elementAtCaret?.node?.elementType == KtTokens.IDENTIFIER) return true
// '(' is considered identifier part if it belongs to primary constructor without 'constructor' keyword
return file.findElementAt(offset)?.getNonStrictParentOfType<KtPrimaryConstructor>()?.textOffset == offset
return elementAtCaret?.getNonStrictParentOfType<KtPrimaryConstructor>()?.textOffset == offset
}
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2010-2017 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.slicer
import com.intellij.psi.PsiElement
import com.intellij.slicer.SliceUsage
import com.intellij.usages.UsagePresentation
import com.intellij.util.Processor
class KotlinSliceDereferenceUsage(
element: PsiElement,
parent: KotlinSliceUsage,
lambdaLevel: Int
) : KotlinSliceUsage(element, parent, lambdaLevel, false) {
override fun processChildren(processor: Processor<SliceUsage>) {
// no children
}
override fun getPresentation() = object : UsagePresentation by super.getPresentation() {
override fun getTooltipText() = "Variable dereferenced"
}
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright 2010-2017 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.slicer
import com.intellij.ide.util.treeView.AbstractTreeStructure
import com.intellij.openapi.actionSystem.DefaultActionGroup
import com.intellij.psi.PsiElement
import com.intellij.slicer.SliceAnalysisParams
import com.intellij.slicer.SliceLanguageSupportProvider
import com.intellij.slicer.SliceTreeBuilder
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.isPlainWithEscapes
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
class KotlinSliceProvider : SliceLanguageSupportProvider {
override fun createRootUsage(element: PsiElement, params: SliceAnalysisParams) = KotlinSliceUsage(element, params)
override fun getExpressionAtCaret(atCaret: PsiElement?, dataFlowToThis: Boolean): PsiElement? {
val element =
atCaret?.parentsWithSelf
?.firstOrNull {
it is KtProperty ||
it is KtParameter ||
it is KtDeclarationWithBody ||
(it is KtExpression && it !is KtDeclaration)
}
?.let { KtPsiUtil.safeDeparenthesize(it as KtExpression) } ?: return null
if (dataFlowToThis) {
if (element is KtConstantExpression) return null
if (element is KtStringTemplateExpression && element.isPlainWithEscapes()) return null
if (element is KtClassLiteralExpression) return null
if (element is KtCallableReferenceExpression) return null
}
return element
}
override fun getElementForDescription(element: PsiElement): PsiElement {
return (element as? KtSimpleNameExpression)?.mainReference?.resolve() ?: element
}
override fun getRenderer() = KotlinSliceUsageCellRenderer
override fun startAnalyzeLeafValues(structure: AbstractTreeStructure, finalRunnable: Runnable) {
}
override fun startAnalyzeNullness(structure: AbstractTreeStructure, finalRunnable: Runnable) {
}
override fun registerExtraPanelActions(group: DefaultActionGroup, builder: SliceTreeBuilder) {
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright 2010-2017 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.slicer
import com.intellij.psi.PsiElement
import com.intellij.slicer.SliceAnalysisParams
import com.intellij.slicer.SliceUsage
import com.intellij.util.Processor
import org.jetbrains.kotlin.psi.KtExpression
open class KotlinSliceUsage : SliceUsage {
val lambdaLevel: Int
val forcedExpressionMode: Boolean
constructor(element: PsiElement, parent: SliceUsage, lambdaLevel: Int, forcedExpressionMode: Boolean) : super(element, parent) {
this.lambdaLevel = lambdaLevel
this.forcedExpressionMode = forcedExpressionMode
}
constructor(element: PsiElement, params: SliceAnalysisParams) : super(element, params) {
this.lambdaLevel = 0
this.forcedExpressionMode = false
}
override fun copy(): KotlinSliceUsage {
val element = usageInfo.element!!
if (parent == null) return KotlinSliceUsage(element, params)
return KotlinSliceUsage(element, parent, lambdaLevel, forcedExpressionMode)
}
public override fun processUsagesFlownDownTo(element: PsiElement, uniqueProcessor: Processor<SliceUsage>) {
InflowSlicer(element as? KtExpression ?: return, uniqueProcessor, this).processChildren()
}
public override fun processUsagesFlownFromThe(element: PsiElement, uniqueProcessor: Processor<SliceUsage>) {
OutflowSlicer(element as? KtExpression ?: return, uniqueProcessor, this).processChildren()
}
}

View File

@@ -0,0 +1,67 @@
/*
* Copyright 2010-2017 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.slicer
import com.intellij.slicer.SliceUsage
import com.intellij.slicer.SliceUsageCellRendererBase
import com.intellij.ui.JBColor
import com.intellij.ui.SimpleTextAttributes
import com.intellij.util.FontUtil
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.parents
import org.jetbrains.kotlin.renderer.ParameterNameRenderingPolicy
// Based on com.intellij.slicer.SliceUsageCellRenderer
object KotlinSliceUsageCellRenderer : SliceUsageCellRendererBase() {
private val descriptorRenderer = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.withOptions {
withDefinedIn = true
withoutTypeParameters = true
parameterNameRenderingPolicy = ParameterNameRenderingPolicy.NONE
includeAdditionalModifiers = false
withoutSuperTypes = true
}
override fun customizeCellRendererFor(sliceUsage: SliceUsage) {
if (sliceUsage !is KotlinSliceUsage) return
val isDereference = sliceUsage is KotlinSliceDereferenceUsage
for ((i, textChunk) in sliceUsage.getText().withIndex()) {
var attributes = textChunk.simpleAttributesIgnoreBackground
if (isDereference) {
attributes = attributes.derive(attributes.style, JBColor.LIGHT_GRAY, attributes.bgColor, attributes.waveColor)
}
append(textChunk.text, attributes)
if (i == 0) {
append(FontUtil.spaceAndThinSpace())
}
}
append(" (Tracking enclosing lambda)".repeat(sliceUsage.lambdaLevel), SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES)
val declaration = sliceUsage.element?.parents?.firstOrNull {
it is KtClass ||
it is KtObjectDeclaration && !it.isObjectLiteral() ||
it is KtDeclarationWithBody ||
it is KtProperty && it.isLocal
} as? KtDeclaration ?: return
val descriptor = declaration.resolveToDescriptor()
append(" in ${descriptorRenderer.render(descriptor)}", SimpleTextAttributes.GRAY_ATTRIBUTES)
}
}

View File

@@ -0,0 +1,141 @@
/*
* Copyright 2010-2017 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.slicer
import com.intellij.analysis.AnalysisScope
import com.intellij.openapi.Disposable
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Disposer
import com.intellij.openapi.wm.ToolWindowId
import com.intellij.openapi.wm.ToolWindowManager
import com.intellij.psi.PsiElement
import com.intellij.slicer.DuplicateMap
import com.intellij.slicer.SliceAnalysisParams
import com.intellij.slicer.SlicePanel
import com.intellij.slicer.SliceRootNode
import com.intellij.usageView.UsageInfo
import com.intellij.usageView.UsageViewBundle
import com.intellij.usages.PsiElementUsageTarget
import com.intellij.usages.UsageContextPanel
import com.intellij.usages.UsageView
import com.intellij.usages.UsageViewPresentation
import com.intellij.usages.impl.UsageContextPanelBase
import com.intellij.usages.impl.UsageViewImpl
import org.jetbrains.kotlin.psi.KtDeclaration
import java.awt.BorderLayout
import javax.swing.JLabel
import javax.swing.JPanel
import javax.swing.SwingConstants
sealed class KotlinUsageContextDataFlowPanelBase(
project: Project,
presentation: UsageViewPresentation,
private val isInflow: Boolean
) : UsageContextPanelBase(project, presentation) {
private var panel: JPanel? = null
abstract class ProviderBase : UsageContextPanel.Provider {
override fun isAvailableFor(usageView: UsageView): Boolean {
val target = (usageView as UsageViewImpl).targets.firstOrNull() ?: return false
val element = (target as? PsiElementUsageTarget)?.element
return element is KtDeclaration && element.isValid
}
}
private fun createParams(element: PsiElement): SliceAnalysisParams {
return SliceAnalysisParams().apply {
scope = AnalysisScope(element.project)
dataFlowToThis = isInflow
showInstanceDereferences = true
}
}
protected fun createPanel(element: PsiElement, dataFlowToThis: Boolean): JPanel {
val toolWindow = ToolWindowManager.getInstance(myProject).getToolWindow(ToolWindowId.FIND)
val params = createParams(element)
val rootNode = SliceRootNode(myProject, DuplicateMap(), KotlinSliceUsage(element, params))
return object : SlicePanel(myProject, dataFlowToThis, rootNode, false, toolWindow) {
override fun isToShowAutoScrollButton() = false
override fun isToShowPreviewButton() = false
override fun isToShowCloseButton() = false
override fun isAutoScroll() = false
override fun setAutoScroll(autoScroll: Boolean) {}
override fun isPreview() = false
override fun setPreview(preview: Boolean) {}
}
}
public override fun updateLayoutLater(infos: List<UsageInfo>?) {
if (infos == null) {
removeAll()
val title = UsageViewBundle.message("select.the.usage.to.preview", myPresentation.usagesWord)
add(JLabel(title, SwingConstants.CENTER), BorderLayout.CENTER)
}
else {
val element = infos.firstOrNull()?.element ?: return
if (panel != null) {
Disposer.dispose(panel as Disposable)
}
val panel = createPanel(element, isInflow)
Disposer.register(this, panel as Disposable)
removeAll()
add(panel, BorderLayout.CENTER)
this.panel = panel
}
revalidate()
}
override fun dispose() {
super.dispose()
panel = null
}
}
class KotlinUsageContextDataInflowPanel(
project: Project,
presentation: UsageViewPresentation
) : KotlinUsageContextDataFlowPanelBase(project, presentation, true) {
class Provider : ProviderBase() {
override fun create(usageView: UsageView): UsageContextPanel {
return KotlinUsageContextDataInflowPanel((usageView as UsageViewImpl).project, usageView.getPresentation())
}
override fun getTabTitle() = "Dataflow to Here"
}
}
class KotlinUsageContextDataOutflowPanel(
project: Project,
presentation: UsageViewPresentation
) : KotlinUsageContextDataFlowPanelBase(project, presentation, false) {
class Provider : ProviderBase() {
override fun create(usageView: UsageView): UsageContextPanel {
return KotlinUsageContextDataOutflowPanel((usageView as UsageViewImpl).project, usageView.getPresentation())
}
override fun getTabTitle() = "Dataflow from Here"
}
}

View File

@@ -0,0 +1,465 @@
/*
* Copyright 2010-2017 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.slicer
import com.intellij.analysis.AnalysisScope
import com.intellij.codeInsight.highlighting.ReadWriteAccessDetector.Access
import com.intellij.psi.PsiElement
import com.intellij.psi.search.LocalSearchScope
import com.intellij.psi.search.SearchScope
import com.intellij.slicer.SliceUsage
import com.intellij.usageView.UsageInfo
import com.intellij.util.Processor
import org.jetbrains.kotlin.asJava.namedUnwrappedElement
import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor
import org.jetbrains.kotlin.cfg.pseudocode.PseudoValue
import org.jetbrains.kotlin.cfg.pseudocode.Pseudocode
import org.jetbrains.kotlin.cfg.pseudocode.containingDeclarationForPseudocode
import org.jetbrains.kotlin.cfg.pseudocode.getContainingPseudocode
import org.jetbrains.kotlin.cfg.pseudocode.instructions.Instruction
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.*
import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.ReturnValueInstruction
import org.jetbrains.kotlin.cfg.pseudocodeTraverser.TraversalOrder
import org.jetbrains.kotlin.cfg.pseudocodeTraverser.traverse
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource
import org.jetbrains.kotlin.descriptors.VariableDescriptorWithAccessors
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
import org.jetbrains.kotlin.idea.findUsages.KotlinFunctionFindUsagesOptions
import org.jetbrains.kotlin.idea.findUsages.KotlinPropertyFindUsagesOptions
import org.jetbrains.kotlin.idea.findUsages.processAllExactUsages
import org.jetbrains.kotlin.idea.refactoring.changeSignature.KotlinValVar
import org.jetbrains.kotlin.idea.refactoring.changeSignature.toValVar
import org.jetbrains.kotlin.idea.search.declarationsSearch.HierarchySearchRequest
import org.jetbrains.kotlin.idea.search.declarationsSearch.searchOverriders
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReadWriteAccessDetector
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument
import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
import org.jetbrains.kotlin.resolve.source.getPsi
import java.util.*
private fun KtDeclaration.processHierarchyDownward(scope: SearchScope, processor: KtDeclaration.() -> Unit) {
processor()
HierarchySearchRequest(this, scope).searchOverriders().forEach {
(it.namedUnwrappedElement as? KtDeclaration)?.processor()
}
}
private fun KtDeclaration.processHierarchyUpward(scope: AnalysisScope, processor: KtDeclaration.() -> Unit) {
processor()
val descriptor = resolveToDescriptor() as? CallableMemberDescriptor ?: return
DescriptorUtils
.getAllOverriddenDescriptors(descriptor)
.mapNotNull { it.source.getPsi() as? KtDeclaration }
.filter { scope.contains(it) }
.forEach(processor)
}
private fun KtFunction.processCalls(scope: SearchScope, processor: (UsageInfo) -> Unit) {
processAllExactUsages(
{
KotlinFunctionFindUsagesOptions(project).apply {
isSearchForTextOccurrences = false
isSkipImportStatements = true
searchScope = scope.intersectWith(useScope)
}
},
processor
)
}
private fun KtDeclaration.processVariableAccesses(
scope: SearchScope,
kind: Access,
processor: (UsageInfo) -> Unit
) {
processAllExactUsages(
{
KotlinPropertyFindUsagesOptions(project).apply {
isReadAccess = kind == Access.Read || kind == Access.ReadWrite
isWriteAccess = kind == Access.Write || kind == Access.ReadWrite
isReadWriteAccess = kind == Access.ReadWrite
isSearchForTextOccurrences = false
isSkipImportStatements = true
searchScope = scope.intersectWith(useScope)
}
},
processor
)
}
private fun KtParameter.canProcess(): Boolean {
return !(isLoopParameter || isVarArg)
}
abstract class Slicer(
protected val element: KtExpression,
protected val processor: Processor<SliceUsage>,
protected val parentUsage: KotlinSliceUsage
) {
protected class PseudocodeCache {
private val computedPseudocodes = HashMap<KtElement, Pseudocode>()
operator fun get(element: KtElement): Pseudocode? {
val container = element.containingDeclarationForPseudocode ?: return null
computedPseudocodes[container]?.let { return it }
return container.getContainingPseudocode(container.analyzeFully())?.apply { computedPseudocodes[container] = this }
}
}
protected val pseudocodeCache = PseudocodeCache()
protected fun PsiElement.passToProcessor(
lambdaLevel: Int = parentUsage.lambdaLevel,
forcedExpressionMode: Boolean = false
) {
processor.process(KotlinSliceUsage(this, parentUsage, lambdaLevel, forcedExpressionMode))
}
protected fun KtDeclaration.processHierarchyDownwardAndPass() {
processHierarchyDownward(parentUsage.scope.toSearchScope()) { passToProcessor() }
}
abstract fun processChildren()
}
class InflowSlicer(
element: KtExpression,
processor: Processor<SliceUsage>,
parentUsage: KotlinSliceUsage
) : Slicer(element, processor, parentUsage) {
private fun PsiElement.passToProcessorAsValue(lambdaLevel: Int = parentUsage.lambdaLevel) = passToProcessor(lambdaLevel, true)
private fun KtDeclaration.processAssignments(accessSearchScope: SearchScope) {
processVariableAccesses(accessSearchScope, Access.Write) body@ {
val refExpression = it.element as? KtExpression ?: return@body
val rhs = KtPsiUtil.safeDeparenthesize(refExpression).getAssignmentByLHS()?.right ?: return@body
rhs.passToProcessorAsValue()
}
}
private fun KtPropertyAccessor.processBackingFieldAssignments() {
forEachDescendantOfType<KtBinaryExpression> body@ {
if (it.operationToken != KtTokens.EQ) return@body
val lhs = it.left?.let { KtPsiUtil.safeDeparenthesize(it) } ?: return@body
val rhs = it.right ?: return@body
if (!lhs.isBackingFieldReference()) return@body
rhs.passToProcessor()
}
}
private fun KtProperty.processPropertyAssignments() {
val analysisScope = parentUsage.scope.toSearchScope()
val accessSearchScope = if (isVar) analysisScope
else {
val containerScope = getStrictParentOfType<KtDeclaration>()?.let { LocalSearchScope(it) } ?: return
analysisScope.intersectWith(containerScope)
}
processAssignments(accessSearchScope)
}
private fun KtProperty.processProperty() {
val bindingContext by lazy { analyzeFully() }
initializer?.passToProcessor()
if (hasDelegateExpression()) {
val getter = (resolveToDescriptor() as VariableDescriptorWithAccessors).getter
val delegateGetterResolvedCall = getter?.let { bindingContext[BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, it] }
(delegateGetterResolvedCall?.resultingDescriptor?.source?.getPsi() as? KtDeclarationWithBody)?.passToProcessor()
}
getter?.processFunction()
val isDefaultGetter = getter?.bodyExpression == null
val isDefaultSetter = setter?.bodyExpression == null
if (isDefaultGetter) {
if (isDefaultSetter) {
processPropertyAssignments()
}
else {
setter!!.processBackingFieldAssignments()
}
}
}
private fun KtParameter.processParameter() {
if (!canProcess()) return
val function = ownerFunction ?: return
if (function.isOverridable()) return
if (function is KtPropertyAccessor && function.isSetter) {
function.property.processPropertyAssignments()
return
}
val parameterDescriptor = analyze()[BindingContext.VALUE_PARAMETER, this] ?: return
(function as? KtFunction)?.processCalls(parentUsage.scope.toSearchScope()) body@ {
val refExpression = it.element as? KtExpression ?: return@body
val callElement = refExpression.getParentOfTypeAndBranch<KtCallElement> { calleeExpression } ?: return@body
val resolvedCall = callElement.getResolvedCall(callElement.analyze()) ?: return@body
val resolvedArgument = resolvedCall.valueArguments[parameterDescriptor] ?: return@body
val flownExpression = when (resolvedArgument) {
is DefaultValueArgument -> defaultValue
is ExpressionValueArgument -> resolvedArgument.valueArgument?.getArgumentExpression()
else -> null
} ?: return@body
flownExpression.passToProcessorAsValue()
}
if (valOrVarKeyword.toValVar() == KotlinValVar.Var) {
processAssignments(parentUsage.scope.toSearchScope())
}
}
private fun KtDeclarationWithBody.processFunction() {
val bodyExpression = bodyExpression ?: return
val pseudocode = pseudocodeCache[bodyExpression] ?: return
pseudocode.traverse(TraversalOrder.FORWARD) { instr ->
if (instr is ReturnValueInstruction && instr.subroutine == this) {
(instr.returnExpressionIfAny?.returnedExpression ?: instr.element as? KtExpression)?.passToProcessorAsValue()
}
}
}
private fun Instruction.passInputsToProcessor() {
inputValues.forEach {
if (it.createdAt != null) {
it.element?.passToProcessorAsValue()
}
}
}
private fun KtExpression.isBackingFieldReference(): Boolean {
return this is KtSimpleNameExpression &&
getReferencedName() == SyntheticFieldDescriptor.NAME.asString() &&
analyze()[BindingContext.REFERENCE_TARGET, this] is SyntheticFieldDescriptor
}
private fun KtExpression.processExpression() {
val lambda = when (this) {
is KtLambdaExpression -> functionLiteral
is KtNamedFunction -> if (name == null) this else null
else -> null
}
if (lambda != null) {
if (parentUsage.lambdaLevel > 0) {
lambda.passToProcessor(parentUsage.lambdaLevel - 1)
}
return
}
val pseudocode = pseudocodeCache[this] ?: return
val expressionValue = pseudocode.getElementValue(this) ?: return
val createdAt = expressionValue.createdAt
when (createdAt) {
is ReadValueInstruction -> {
if (createdAt.target == AccessTarget.BlackBox) {
val originalElement = expressionValue.element as? KtExpression ?: return
if (originalElement != this) {
originalElement.processExpression()
}
return
}
val accessedDescriptor = createdAt.target.accessedDescriptor ?: return
val accessedDeclaration = accessedDescriptor.source.getPsi() as? KtDeclaration ?: return
if (accessedDescriptor is SyntheticFieldDescriptor) {
val property = accessedDeclaration as? KtProperty ?: return
if (accessedDescriptor.propertyDescriptor.setter?.isDefault ?: true) {
property.processPropertyAssignments()
}
else {
property.setter?.processBackingFieldAssignments()
}
return
}
accessedDeclaration.processHierarchyDownwardAndPass()
}
is MergeInstruction -> createdAt.passInputsToProcessor()
is MagicInstruction -> when (createdAt.kind) {
MagicKind.NOT_NULL_ASSERTION, MagicKind.CAST -> createdAt.passInputsToProcessor()
MagicKind.BOUND_CALLABLE_REFERENCE, MagicKind.UNBOUND_CALLABLE_REFERENCE -> {
val callableRefExpr = expressionValue.element as? KtCallableReferenceExpression ?: return
val referencedDescriptor = analyze()[BindingContext.REFERENCE_TARGET, callableRefExpr.callableReference] ?: return
val referencedDeclaration = (referencedDescriptor as? DeclarationDescriptorWithSource)?.source?.getPsi() ?: return
referencedDeclaration.passToProcessor(parentUsage.lambdaLevel - 1)
}
else -> return
}
is CallInstruction -> {
val resolvedCall = createdAt.resolvedCall
val resultingDescriptor = resolvedCall.resultingDescriptor
if (resultingDescriptor is FunctionInvokeDescriptor) {
(resolvedCall.dispatchReceiver as? ExpressionReceiver)?.expression?.passToProcessorAsValue(parentUsage.lambdaLevel + 1)
}
else {
(resultingDescriptor.source.getPsi() as? KtDeclaration)?.processHierarchyDownwardAndPass()
}
}
}
}
override fun processChildren() {
if (parentUsage.forcedExpressionMode) return element.processExpression()
when (element) {
is KtProperty -> element.processProperty()
is KtParameter -> element.processParameter()
is KtDeclarationWithBody -> element.processFunction()
else -> element.processExpression()
}
}
}
class OutflowSlicer(
element: KtExpression,
processor: Processor<SliceUsage>,
parentUsage: KotlinSliceUsage
) : Slicer(element, processor, parentUsage) {
private fun KtDeclaration.processVariable() {
processHierarchyUpward(parentUsage.scope) {
if (this is KtParameter && !canProcess()) return@processHierarchyUpward
val withDereferences = parentUsage.params.showInstanceDereferences
processVariableAccesses(parentUsage.scope.toSearchScope(), if (withDereferences) Access.ReadWrite else Access.Read) body@ {
val refExpression = (it.element as? KtExpression)?.let { KtPsiUtil.safeDeparenthesize(it) } ?: return@body
if (withDereferences) {
refExpression.processDereferences()
}
if (!withDereferences || KotlinReadWriteAccessDetector.INSTANCE.getExpressionAccess(refExpression) == Access.Read) {
refExpression.processExpression()
}
}
}
}
private fun PsiElement.getCallElementForExactCallee(): KtCallElement? {
val parentCall = getParentOfTypeAndBranch<KtCallElement> { calleeExpression } ?: return null
val callee = parentCall.calleeExpression?.let { KtPsiUtil.safeDeparenthesize(it) }
if (callee == this || callee is KtConstructorCalleeExpression && callee.isAncestor(this, true)) return parentCall
return null
}
private fun PsiElement.getCallableReferenceForExactCallee(): KtCallableReferenceExpression? {
val callableRef = getParentOfTypeAndBranch<KtCallableReferenceExpression> { callableReference } ?: return null
val callee = KtPsiUtil.safeDeparenthesize(callableRef.callableReference)
return if (callee == this) callableRef else null
}
private fun KtFunction.processFunction() {
if (this is KtConstructor<*> || this is KtNamedFunction && name != null) {
processHierarchyUpward(parentUsage.scope) {
(this as? KtFunction)?.processCalls(parentUsage.scope.toSearchScope()) {
it.element?.getCallElementForExactCallee()?.passToProcessor()
it.element?.getCallableReferenceForExactCallee()?.passToProcessor(parentUsage.lambdaLevel + 1)
}
}
return
}
val funExpression = when (this) {
is KtFunctionLiteral -> parent as? KtLambdaExpression
is KtNamedFunction -> this
else -> null
} ?: return
(funExpression as PsiElement).passToProcessor(parentUsage.lambdaLevel + 1, true)
}
private fun processDereferenceIsNeeded(
expression: KtExpression,
pseudoValue: PseudoValue,
instr: InstructionWithReceivers
) {
if (!parentUsage.params.showInstanceDereferences) return
val receiver = instr.receiverValues[pseudoValue]
val resolvedCall = when (instr) {
is CallInstruction -> instr.resolvedCall
is AccessValueInstruction -> (instr.target as? AccessTarget.Call)?.resolvedCall
else -> null
} ?: return
if (receiver != null && resolvedCall.dispatchReceiver == receiver) {
processor.process(KotlinSliceDereferenceUsage(expression, parentUsage, parentUsage.lambdaLevel))
}
}
private fun KtExpression.processPseudocodeUsages(processor: (PseudoValue, Instruction) -> Unit) {
val pseudocode = pseudocodeCache[this] ?: return
val pseudoValue = pseudocode.getElementValue(this) ?: return
pseudocode.getUsages(pseudoValue).forEach { processor(pseudoValue, it) }
}
private fun KtExpression.processDereferences() {
processPseudocodeUsages { pseudoValue, instr ->
when (instr) {
is ReadValueInstruction -> processDereferenceIsNeeded(this, pseudoValue, instr)
is CallInstruction -> processDereferenceIsNeeded(this, pseudoValue, instr)
}
}
}
private fun KtExpression.processExpression() {
processPseudocodeUsages { pseudoValue, instr ->
when (instr) {
is WriteValueInstruction -> (instr.target.accessedDescriptor?.source?.getPsi() as? KtDeclaration)?.passToProcessor()
is CallInstruction -> {
if (parentUsage.lambdaLevel > 0 && instr.receiverValues[pseudoValue] != null) {
instr.element.passToProcessor(parentUsage.lambdaLevel - 1)
}
else {
instr.arguments[pseudoValue]?.source?.getPsi()?.passToProcessor()
}
}
is ReturnValueInstruction -> instr.subroutine.passToProcessor()
is MagicInstruction -> when (instr.kind) {
MagicKind.NOT_NULL_ASSERTION, MagicKind.CAST -> instr.outputValue.element?.passToProcessor()
else -> {
}
}
}
}
}
override fun processChildren() {
if (parentUsage.forcedExpressionMode) return element.processExpression()
when (element) {
is KtProperty, is KtParameter -> (element as KtDeclaration).processVariable()
is KtFunction -> element.processFunction()
is KtPropertyAccessor -> if (element.isGetter) {
element.property.processVariable()
}
else -> element.processExpression()
}
}
}

View File

@@ -0,0 +1,6 @@
package foo
class X {
val a: X = X()
val b: B = B()
}

View File

@@ -0,0 +1,11 @@
package foo
class A {
val a: A = A()
val b: B = B()
}
class B {
val a: A = A()
val b: B = B()
}

View File

@@ -0,0 +1,11 @@
package foo
class <caret>A {
val a: A = A()
val b: B = B()
}
class B {
val a: A = A()
val b: B = B()
}

View File

@@ -0,0 +1,5 @@
{
"mainFile": "foo/test.kt",
"targetPackage": "foo",
"newName": "X"
}

View File

@@ -0,0 +1,5 @@
package foo;
public class J {
public static int JJJ = 1;
}

View File

@@ -0,0 +1,7 @@
package foo
import foo.J.JJJ
fun test() {
val x = JJJ
}

View File

@@ -0,0 +1,5 @@
package foo
fun test2() {
val x = J.JJJ
}

View File

@@ -0,0 +1,5 @@
package foo;
public class J {
public static int JJJ = 1;
}

View File

@@ -0,0 +1,7 @@
package foo
import foo.J.JJJ
fun <caret>test() {
val x = JJJ
}

View File

@@ -0,0 +1,5 @@
{
"mainFile": "foo/test.kt",
"targetPackage": "foo",
"newName": "test2"
}

View File

@@ -0,0 +1,7 @@
package foo;
public class J {
public static void jjj() {
}
}

View File

@@ -0,0 +1,7 @@
package foo
import foo.J.jjj
fun test() {
jjj()
}

View File

@@ -0,0 +1,5 @@
package foo
fun test2() {
J.jjj()
}

View File

@@ -0,0 +1,7 @@
package foo;
public class J {
public static void jjj() {
}
}

View File

@@ -0,0 +1,7 @@
package foo
import foo.J.jjj
fun <caret>test() {
jjj()
}

View File

@@ -0,0 +1,5 @@
{
"mainFile": "foo/test.kt",
"targetPackage": "foo",
"newName": "test2"
}

View File

@@ -0,0 +1,3 @@
class Foo {
}

View File

@@ -0,0 +1,5 @@
import Foo as Baz
fun test() {
val bar: Baz = Baz()
}

View File

@@ -0,0 +1,3 @@
class Foo {
}

View File

@@ -0,0 +1,5 @@
import Foo as Bar
fun test() {
val bar: /*rename*/Bar = Bar()
}

View File

@@ -0,0 +1,5 @@
{
"type": "AUTO_DETECT",
"mainFile": "test.kt",
"newName": "Baz"
}

View File

@@ -0,0 +1,5 @@
fun <R> foo(f: () -> R) = f()
fun test() {
foo bar@ { return@bar false }
}

View File

@@ -0,0 +1,5 @@
fun <R> foo(f: () -> R) = f()
fun test() {
foo bar@ { return@bar /*rename*/ false }
}

View File

@@ -0,0 +1,5 @@
{
"type": "AUTO_DETECT",
"mainFile": "test.kt",
"newName": "baz"
}

View File

@@ -0,0 +1,5 @@
fun <R> foo(f: () -> R) = f()
fun test() {
foo bar@ { return@bar false }
}

View File

@@ -0,0 +1,5 @@
fun <R> foo(f: () -> R) = f()
fun test() {
foo bar@ { return/*rename*/@bar false }
}

View File

@@ -0,0 +1,5 @@
{
"type": "AUTO_DETECT",
"mainFile": "test.kt",
"newName": "baz"
}

View File

@@ -0,0 +1,7 @@
fun <R> foo(f: () -> R) = f()
fun test() {
foo {
return@foo false
}
}

View File

@@ -0,0 +1,7 @@
fun <R> foo(f: () -> R) = f()
fun test() {
foo {
return/*rename*/@foo false
}
}

View File

@@ -0,0 +1,5 @@
{
"type": "AUTO_DETECT",
"mainFile": "test.kt",
"newName": "bar"
}

View File

@@ -0,0 +1,7 @@
fun <R> foo(f: () -> R) = f()
fun test() {
foo {
return@foo false
}
}

View File

@@ -0,0 +1,7 @@
fun <R> foo(f: () -> R) = f()
fun test() {
foo {
return/*rename*/@foo false
}
}

View File

@@ -0,0 +1,5 @@
{
"type": "AUTO_DETECT",
"mainFile": "test.kt",
"newName": "bar"
}

View File

@@ -0,0 +1,8 @@
fun `fun`(n: Int) {
}
fun test() {
`fun`(1)
`fun`(2)
}

View File

@@ -0,0 +1,8 @@
fun /*rename*/foo(n: Int) {
}
fun test() {
foo(1)
foo(2)
}

View File

@@ -0,0 +1,5 @@
{
"type": "MARKED_ELEMENT",
"mainFile": "test.kt",
"newName": "`fun`"
}

View File

@@ -0,0 +1,9 @@
import Foo.foo as baz
object Foo {
fun foo() {}
}
fun test() {
baz()
}

View File

@@ -0,0 +1,9 @@
import Foo.foo as bar
object Foo {
fun foo() {}
}
fun test() {
/*rename*/bar()
}

View File

@@ -0,0 +1,5 @@
{
"type": "AUTO_DETECT",
"mainFile": "test.kt",
"newName": "baz"
}

View File

@@ -0,0 +1,9 @@
import Foo.foo as baz
object Foo {
val foo = 1
}
fun test() {
val x = baz
}

View File

@@ -0,0 +1,9 @@
import Foo.foo as bar
object Foo {
val foo = 1
}
fun test() {
val x = /*rename*/bar
}

View File

@@ -0,0 +1,5 @@
{
"type": "AUTO_DETECT",
"mainFile": "test.kt",
"newName": "baz"
}

View File

@@ -0,0 +1,8 @@
fun foo(n: Int) {
}
fun test() {
foo(1)
foo(2)
}

View File

@@ -0,0 +1,8 @@
fun /*rename*/`fun`(n: Int) {
}
fun test() {
`fun`(1)
`fun`(2)
}

View File

@@ -0,0 +1,5 @@
{
"type": "MARKED_ELEMENT",
"mainFile": "test.kt",
"newName": "foo"
}

View File

@@ -0,0 +1,8 @@
fun foo(n: Int) {
}
fun test() {
foo(1)
foo(2)
}

View File

@@ -0,0 +1,8 @@
fun `fun`/*rename*/(n: Int) {
}
fun test() {
`fun`(1)
`fun`(2)
}

View File

@@ -0,0 +1,5 @@
{
"type": "MARKED_ELEMENT",
"mainFile": "test.kt",
"newName": "foo"
}

View File

@@ -0,0 +1,9 @@
// FLOW: IN
fun foo(f: (Int) -> Int): Int {
return f(1)
}
fun test() {
val <caret>x = foo(fun(n: Int) = n)
}

View File

@@ -0,0 +1,10 @@
8 val <bold>x = foo(fun(n: Int) = n)</bold>
8 val x = <bold>foo(fun(n: Int) = n)</bold>
3 fun <bold>foo(f: (Int) -> Int): Int {</bold>
4 return <bold>f(1)</bold>
4 [LAMBDA] return <bold>f</bold>(1)
3 [LAMBDA] fun foo(<bold>f: (Int) -> Int</bold>): Int {
8 [LAMBDA] val x = foo(<bold>fun(n: Int) = n</bold>)
8 val x = foo(<bold>fun(n: Int) = n</bold>)
8 val x = foo(fun(n: Int) = <bold>n</bold>)
8 val x = foo(fun(<bold>n: Int</bold>) = n)

View File

@@ -0,0 +1,9 @@
// FLOW: IN
fun foo(f: (Int) -> Int): Int {
return f(1)
}
fun test() {
val <caret>x = foo(fun(n: Int): Int { return n })
}

View File

@@ -0,0 +1,10 @@
8 val <bold>x = foo(fun(n: Int): Int { return n })</bold>
8 val x = <bold>foo(fun(n: Int): Int { return n })</bold>
3 fun <bold>foo(f: (Int) -> Int): Int {</bold>
4 return <bold>f(1)</bold>
4 [LAMBDA] return <bold>f</bold>(1)
3 [LAMBDA] fun foo(<bold>f: (Int) -> Int</bold>): Int {
8 [LAMBDA] val x = foo(<bold>fun(n: Int): Int { return n }</bold>)
8 val x = foo(<bold>fun(n: Int): Int { return n }</bold>)
8 val x = foo(fun(n: Int): Int { return <bold>n</bold> })
8 val x = foo(fun(<bold>n: Int</bold>): Int { return n })

5
idea/testData/slicer/inflow/cast.kt vendored Normal file
View File

@@ -0,0 +1,5 @@
// FLOW: IN
fun test(o: Any) {
val <caret>x = o as String
}

View File

@@ -0,0 +1,4 @@
4 val <bold>x = o as String</bold>
4 val x = <bold>o as String</bold>
4 val x = <bold>o</bold> as String
3 fun test(<bold>o: Any</bold>) {

View File

@@ -0,0 +1,13 @@
// FLOW: IN
class A(var b: Boolean) {
var foo: Int
set(value) {
field = if (b) value else 0
}
fun test() {
val x = <caret>foo
foo = 1
}
}

View File

@@ -0,0 +1,7 @@
10 val x = <bold>foo</bold>
4 var <bold>foo: Int</bold>
6 field = <bold>if (b) value else 0</bold>
6 field = if (b) <bold>value</bold> else 0
5 set(<bold>value</bold>) {
11 foo = <bold>1</bold>
6 field = if (b) value else <bold>0</bold>

View File

@@ -0,0 +1,13 @@
// FLOW: IN
import kotlin.reflect.KProperty
object D {
operator fun getValue(thisRef: Any?, property: KProperty<*>) = 1
}
val foo: Int by D
fun test() {
val <caret>x = foo
}

View File

@@ -0,0 +1,5 @@
12 val <bold>x = foo</bold>
12 val x = <bold>foo</bold>
9 val <bold>foo: Int by D</bold>
6 operator fun <bold>getValue(thisRef: Any?, property: KProperty<*>) = 1</bold>
6 operator fun getValue(thisRef: Any?, property: KProperty<*>) = <bold>1</bold>

View File

@@ -0,0 +1,9 @@
// FLOW: IN
fun foo(a: Int, b: Int, f: (Int) -> (Int) -> Int): Int {
return f(a)(b)
}
fun test() {
val <caret>x = foo(1, 2) { { it } }
}

View File

@@ -0,0 +1,12 @@
8 val <bold>x = foo(1, 2) { { it } }</bold>
8 val x = <bold>foo(1, 2) { { it } }</bold>
3 fun <bold>foo(a: Int, b: Int, f: (Int) -> (Int) -> Int): Int {</bold>
4 return <bold>f(a)(b)</bold>
4 [LAMBDA] return <bold>f(a)</bold>(b)
4 [LAMBDA] [LAMBDA] return <bold>f</bold>(a)(b)
3 [LAMBDA] [LAMBDA] fun foo(a: Int, b: Int, <bold>f: (Int) -> (Int) -> Int</bold>): Int {
8 [LAMBDA] [LAMBDA] val x = foo(1, 2) <bold>{ { it } }</bold>
8 [LAMBDA] val x = foo(1, 2) <bold>{ { it } }</bold>
8 [LAMBDA] val x = foo(1, 2) { <bold>{ it }</bold> }
8 val x = foo(1, 2) { <bold>{ it }</bold> }
8 val x = foo(1, 2) { { <bold>it</bold> } }

View File

@@ -0,0 +1,13 @@
// FLOW: IN
fun foo(<caret>n: Int, s: String = "???") {
}
fun test() {
foo(1)
foo(1, "2")
foo(1, s = "2")
foo(n = 1, s = "2")
foo(s = "2", n = 1)
}

View File

@@ -0,0 +1,6 @@
3 fun foo(<bold>n: Int</bold>, s: String = "???") {
8 foo(<bold>1</bold>)
9 foo(<bold>1</bold>, "2")
10 foo(<bold>1</bold>, s = "2")
11 foo(n = <bold>1</bold>, s = "2")
12 foo(s = "2", n = <bold>1</bold>)

View File

@@ -0,0 +1,13 @@
// FLOW: IN
fun foo(n: Int, <caret>s: String = "???") {
}
fun test() {
foo(1)
foo(1, "2")
foo(1, s = "2")
foo(n = 1, s = "2")
foo(s = "2", n = 1)
}

View File

@@ -0,0 +1,6 @@
3 fun foo(n: Int, <bold>s: String = "???"</bold>) {
3 fun foo(n: Int, s: String = <bold>"???"</bold>) {
9 foo(1, <bold>"2"</bold>)
10 foo(1, s = <bold>"2"</bold>)
11 foo(n = 1, s = <bold>"2"</bold>)
12 foo(s = <bold>"2"</bold>, n = 1)

View File

@@ -0,0 +1,10 @@
// FLOW: IN
fun foo(f: (Int) -> Int): Int {
return f(1)
}
fun test() {
fun bar(n: Int) = n
val <caret>x = foo(::bar)
}

View File

@@ -0,0 +1,10 @@
9 val <bold>x = foo(::bar)</bold>
9 val x = <bold>foo(::bar)</bold>
3 fun <bold>foo(f: (Int) -> Int): Int {</bold>
4 return <bold>f(1)</bold>
4 [LAMBDA] return <bold>f</bold>(1)
3 [LAMBDA] fun foo(<bold>f: (Int) -> Int</bold>): Int {
9 [LAMBDA] val x = foo(<bold>::bar</bold>)
8 fun <bold>bar(n: Int) = n</bold>
8 fun bar(n: Int) = <bold>n</bold>
8 fun bar(<bold>n: Int</bold>) = n

View File

@@ -0,0 +1,11 @@
// FLOW: IN
fun foo(f: (Int) -> Int): Int {
return f(1)
}
fun test() {
fun bar(n: Int) = n
val f = ::bar
val <caret>x = foo(f)
}

View File

@@ -0,0 +1,12 @@
10 val <bold>x = foo(f)</bold>
10 val x = <bold>foo(f)</bold>
3 fun <bold>foo(f: (Int) -> Int): Int {</bold>
4 return <bold>f(1)</bold>
4 [LAMBDA] return <bold>f</bold>(1)
3 [LAMBDA] fun foo(<bold>f: (Int) -> Int</bold>): Int {
10 [LAMBDA] val x = foo(<bold>f</bold>)
9 [LAMBDA] val <bold>f = ::bar</bold>
9 [LAMBDA] val f = <bold>::bar</bold>
8 fun <bold>bar(n: Int) = n</bold>
8 fun bar(n: Int) = <bold>n</bold>
8 fun bar(<bold>n: Int</bold>) = n

View File

@@ -0,0 +1,6 @@
// FLOW: IN
fun test() {
fun bar(n: Int) = n
val <caret>x = (::bar)(1)
}

Some files were not shown because too many files have changed in this diff Show More