diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinReferencesSearcher.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinReferencesSearcher.kt index a4049e794a6..42f5263b52e 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinReferencesSearcher.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinReferencesSearcher.kt @@ -24,6 +24,7 @@ import com.intellij.psi.search.SearchRequestCollector import com.intellij.psi.search.SearchScope import com.intellij.psi.search.UsageSearchContext import com.intellij.psi.search.searches.ReferencesSearch +import com.intellij.util.containers.nullize import org.jetbrains.kotlin.asJava.LightClassUtil import org.jetbrains.kotlin.asJava.elements.KtLightField import org.jetbrains.kotlin.asJava.elements.KtLightMember @@ -42,8 +43,11 @@ import org.jetbrains.kotlin.idea.search.usagesSearch.getClassNameForCompanionObj import org.jetbrains.kotlin.idea.search.usagesSearch.operators.OperatorReferenceSearcher import org.jetbrains.kotlin.idea.stubindex.KotlinSourceFilterScope import org.jetbrains.kotlin.idea.util.application.runReadAction +import org.jetbrains.kotlin.idea.util.expectedDeclarationIfAny +import org.jetbrains.kotlin.idea.util.isExpectDeclaration import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType +import org.jetbrains.kotlin.psi.psiUtil.hasActualModifier import org.jetbrains.kotlin.psi.psiUtil.parents import java.util.* @@ -54,7 +58,8 @@ data class KotlinReferencesSearchOptions( val acceptCompanionObjectMembers: Boolean = false, val searchForComponentConventions: Boolean = true, val searchForOperatorConventions: Boolean = true, - val searchNamedArguments: Boolean = true + val searchNamedArguments: Boolean = true, + val searchForExpectedUsages: Boolean = true ) { fun anyEnabled(): Boolean = acceptCallableOverrides || acceptOverloads || acceptExtensionsOfDeclarationClass @@ -94,47 +99,55 @@ class KotlinReferencesSearcher : QueryExecutorBase scope.unionSafe(queryParameters.effectiveSearchScope(e)) } } - val refFilter: (PsiReference) -> Boolean = when (unwrappedElement) { + val refFilter: (PsiReference) -> Boolean = when (elementToSearch) { is KtParameter -> ({ ref: PsiReference -> !ref.isNamedArgumentReference()/* they are processed later*/ }) else -> ({ true }) } - val resultProcessor = KotlinRequestResultProcessor(unwrappedElement, filter = refFilter, options = kotlinOptions) + val resultProcessor = KotlinRequestResultProcessor(elementToSearch, filter = refFilter, options = kotlinOptions) - val name = unwrappedElement.name - if (kotlinOptions.anyEnabled()) { + val name = elementToSearch.name + if (kotlinOptions.anyEnabled() || elementToSearch is KtNamedDeclaration && elementToSearch.isExpectDeclaration()) { if (name != null) { + // Check difference with default scope queryParameters.optimizer.searchWord( - name, effectiveSearchScope, UsageSearchContext.IN_CODE, true, unwrappedElement, resultProcessor + name, effectiveSearchScope, UsageSearchContext.IN_CODE, true, elementToSearch, resultProcessor ) } } - val classNameForCompanionObject = unwrappedElement.getClassNameForCompanionObject() + val classNameForCompanionObject = elementToSearch.getClassNameForCompanionObject() if (classNameForCompanionObject != null) { queryParameters.optimizer.searchWord( - classNameForCompanionObject, effectiveSearchScope, UsageSearchContext.ANY, true, unwrappedElement, resultProcessor + classNameForCompanionObject, effectiveSearchScope, UsageSearchContext.ANY, true, elementToSearch, resultProcessor ) } - if (unwrappedElement is KtParameter && kotlinOptions.searchNamedArguments) { - searchNamedArguments(unwrappedElement) + if (elementToSearch is KtParameter && kotlinOptions.searchNamedArguments) { + searchNamedArguments(elementToSearch) } - if (!(unwrappedElement is KtElement && isOnlyKotlinSearch(effectiveSearchScope))) { + if (!(elementToSearch is KtElement && isOnlyKotlinSearch(effectiveSearchScope))) { searchLightElements(element) } diff --git a/idea/src/org/jetbrains/kotlin/idea/findUsages/handlers/KotlinFindClassUsagesHandler.kt b/idea/src/org/jetbrains/kotlin/idea/findUsages/handlers/KotlinFindClassUsagesHandler.kt index bf43cae4aeb..9c211a37d56 100644 --- a/idea/src/org/jetbrains/kotlin/idea/findUsages/handlers/KotlinFindClassUsagesHandler.kt +++ b/idea/src/org/jetbrains/kotlin/idea/findUsages/handlers/KotlinFindClassUsagesHandler.kt @@ -135,9 +135,14 @@ class KotlinFindClassUsagesHandler( } private fun processClassReferencesLater(classOrObject: KtClassOrObject) { - val searchParameters = KotlinReferencesSearchParameters(classOrObject, - scope = options.searchScope, - kotlinOptions = KotlinReferencesSearchOptions(acceptCompanionObjectMembers = true)) + val searchParameters = KotlinReferencesSearchParameters( + classOrObject, + scope = options.searchScope, + kotlinOptions = KotlinReferencesSearchOptions( + acceptCompanionObjectMembers = true, + searchForExpectedUsages = kotlinOptions.searchExpected + ) + ) var usagesQuery = ReferencesSearch.search(searchParameters) if (kotlinOptions.isSkipImportStatements) { @@ -146,8 +151,7 @@ class KotlinFindClassUsagesHandler( if (!kotlinOptions.searchConstructorUsages) { usagesQuery = FilteredQuery(usagesQuery) { !it.isConstructorUsage(classOrObject) } - } - else if (!options.isUsages) { + } else if (!options.isUsages) { usagesQuery = FilteredQuery(usagesQuery) { it.isConstructorUsage(classOrObject) } } addTask { usagesQuery.forEach(referenceProcessor) } diff --git a/idea/src/org/jetbrains/kotlin/idea/findUsages/handlers/KotlinFindMemberUsagesHandler.kt b/idea/src/org/jetbrains/kotlin/idea/findUsages/handlers/KotlinFindMemberUsagesHandler.kt index 3b2039ee02f..e5abe84baf9 100644 --- a/idea/src/org/jetbrains/kotlin/idea/findUsages/handlers/KotlinFindMemberUsagesHandler.kt +++ b/idea/src/org/jetbrains/kotlin/idea/findUsages/handlers/KotlinFindMemberUsagesHandler.kt @@ -83,7 +83,12 @@ abstract class KotlinFindMemberUsagesHandler protected c override fun createKotlinReferencesSearchOptions(options: FindUsagesOptions): KotlinReferencesSearchOptions { val kotlinOptions = options as KotlinFunctionFindUsagesOptions - return KotlinReferencesSearchOptions(true, kotlinOptions.isIncludeOverloadUsages, kotlinOptions.isIncludeOverloadUsages) + return KotlinReferencesSearchOptions( + acceptCallableOverrides = true, + acceptOverloads = kotlinOptions.isIncludeOverloadUsages, + acceptExtensionsOfDeclarationClass = kotlinOptions.isIncludeOverloadUsages, + searchForExpectedUsages = kotlinOptions.searchExpected + ) } override fun applyQueryFilters(element: PsiElement, options: FindUsagesOptions, query: Query): Query { @@ -142,7 +147,13 @@ abstract class KotlinFindMemberUsagesHandler protected c } override fun createKotlinReferencesSearchOptions(options: FindUsagesOptions): KotlinReferencesSearchOptions { - return KotlinReferencesSearchOptions(true, false, false) + val kotlinOptions = options as KotlinPropertyFindUsagesOptions + return KotlinReferencesSearchOptions( + acceptCallableOverrides = true, + acceptOverloads = false, + acceptExtensionsOfDeclarationClass = false, + searchForExpectedUsages = kotlinOptions.searchExpected + ) } } diff --git a/idea/testData/multiModuleFindUsages/findCommonClassFromActual/common/common.kt b/idea/testData/multiModuleFindUsages/findCommonClassFromActual/common/common.kt new file mode 100644 index 00000000000..f5c5fddd11c --- /dev/null +++ b/idea/testData/multiModuleFindUsages/findCommonClassFromActual/common/common.kt @@ -0,0 +1,8 @@ +fun test() { + My("a").boo() + My("b").boo() +} + +expect class My(val s: String) { + fun boo() +} \ No newline at end of file diff --git a/idea/testData/multiModuleFindUsages/findCommonClassFromActual/jvm/jvm.kt b/idea/testData/multiModuleFindUsages/findCommonClassFromActual/jvm/jvm.kt new file mode 100644 index 00000000000..7a811244b00 --- /dev/null +++ b/idea/testData/multiModuleFindUsages/findCommonClassFromActual/jvm/jvm.kt @@ -0,0 +1,6 @@ +// PSI_ELEMENT: org.jetbrains.kotlin.psi.KtClass +// OPTIONS: usages, expected + +actual class My(val s: String) { + actual fun boo() {} +} diff --git a/idea/testData/multiModuleFindUsages/findCommonClassFromActual/jvm/jvm.results.txt b/idea/testData/multiModuleFindUsages/findCommonClassFromActual/jvm/jvm.results.txt new file mode 100644 index 00000000000..b4a2ecbc812 --- /dev/null +++ b/idea/testData/multiModuleFindUsages/findCommonClassFromActual/jvm/jvm.results.txt @@ -0,0 +1,2 @@ +[common.kt] New instance creation 2 My("a").boo() +[common.kt] New instance creation 3 My("b").boo() \ No newline at end of file diff --git a/idea/testData/multiModuleFindUsages/findCommonFromActual/jvm/jvm.kt b/idea/testData/multiModuleFindUsages/findCommonFromActual/jvm/jvm.kt index 67f5290b623..73150bf0ea3 100644 --- a/idea/testData/multiModuleFindUsages/findCommonFromActual/jvm/jvm.kt +++ b/idea/testData/multiModuleFindUsages/findCommonFromActual/jvm/jvm.kt @@ -1,4 +1,4 @@ // PSI_ELEMENT: org.jetbrains.kotlin.psi.KtNamedFunction -// OPTIONS: usages +// OPTIONS: usages, expected actual fun boo(s: String) {} \ No newline at end of file diff --git a/idea/testData/multiModuleFindUsages/findCommonFromActual/jvm/jvm.results.txt b/idea/testData/multiModuleFindUsages/findCommonFromActual/jvm/jvm.results.txt index e69de29bb2d..f5c254b47ac 100644 --- a/idea/testData/multiModuleFindUsages/findCommonFromActual/jvm/jvm.results.txt +++ b/idea/testData/multiModuleFindUsages/findCommonFromActual/jvm/jvm.results.txt @@ -0,0 +1,2 @@ +[common.kt] Function call 2 boo("a") +[common.kt] Function call 3 boo("b") \ No newline at end of file diff --git a/idea/testData/multiModuleFindUsages/findCommonPropertyFromActual/common/common.kt b/idea/testData/multiModuleFindUsages/findCommonPropertyFromActual/common/common.kt new file mode 100644 index 00000000000..93d0653f3d1 --- /dev/null +++ b/idea/testData/multiModuleFindUsages/findCommonPropertyFromActual/common/common.kt @@ -0,0 +1,8 @@ +fun test() { + use(boo) + use(boo) +} + +fun use(arg: Int) {} + +expect val boo: Int \ No newline at end of file diff --git a/idea/testData/multiModuleFindUsages/findCommonPropertyFromActual/jvm/jvm.kt b/idea/testData/multiModuleFindUsages/findCommonPropertyFromActual/jvm/jvm.kt new file mode 100644 index 00000000000..bc844ee1872 --- /dev/null +++ b/idea/testData/multiModuleFindUsages/findCommonPropertyFromActual/jvm/jvm.kt @@ -0,0 +1,4 @@ +// PSI_ELEMENT: org.jetbrains.kotlin.psi.KtProperty +// OPTIONS: usages, expected + +actual val boo: Int get() = 42 \ No newline at end of file diff --git a/idea/testData/multiModuleFindUsages/findCommonPropertyFromActual/jvm/jvm.results.txt b/idea/testData/multiModuleFindUsages/findCommonPropertyFromActual/jvm/jvm.results.txt new file mode 100644 index 00000000000..e8b3b536209 --- /dev/null +++ b/idea/testData/multiModuleFindUsages/findCommonPropertyFromActual/jvm/jvm.results.txt @@ -0,0 +1,2 @@ +[common.kt] Value read 2 use(boo) +[common.kt] Value read 3 use(boo) \ No newline at end of file diff --git a/idea/testData/refactoring/safeDeleteMultiModule/byImplClassMemberFun/conflicts.txt b/idea/testData/refactoring/safeDeleteMultiModule/byImplClassMemberFun/conflicts.txt index 2327685c225..d59ed5f87c4 100644 --- a/idea/testData/refactoring/safeDeleteMultiModule/byImplClassMemberFun/conflicts.txt +++ b/idea/testData/refactoring/safeDeleteMultiModule/byImplClassMemberFun/conflicts.txt @@ -1 +1 @@ -function Foo.foo(Int) has 1 usage that is not safe to delete. \ No newline at end of file +function Foo.foo(Int) has 2 usages that are not safe to delete. \ No newline at end of file diff --git a/idea/testData/refactoring/safeDeleteMultiModule/byImplClassMemberVal/conflicts.txt b/idea/testData/refactoring/safeDeleteMultiModule/byImplClassMemberVal/conflicts.txt index bf5bfd4809c..c1d173618d8 100644 --- a/idea/testData/refactoring/safeDeleteMultiModule/byImplClassMemberVal/conflicts.txt +++ b/idea/testData/refactoring/safeDeleteMultiModule/byImplClassMemberVal/conflicts.txt @@ -1 +1 @@ -property Foo.foo has 1 usage that is not safe to delete. \ No newline at end of file +property Foo.foo has 2 usages that are not safe to delete. \ No newline at end of file diff --git a/idea/testData/refactoring/safeDeleteMultiModule/byImplClassSecondaryConstructor/conflicts.txt b/idea/testData/refactoring/safeDeleteMultiModule/byImplClassSecondaryConstructor/conflicts.txt index e12498168da..84f3d45a75f 100644 --- a/idea/testData/refactoring/safeDeleteMultiModule/byImplClassSecondaryConstructor/conflicts.txt +++ b/idea/testData/refactoring/safeDeleteMultiModule/byImplClassSecondaryConstructor/conflicts.txt @@ -1 +1 @@ -constructor Foo(Int) has 1 usage that is not safe to delete. +constructor Foo(Int) has 2 usages that are not safe to delete. diff --git a/idea/testData/refactoring/safeDeleteMultiModule/byImplFun/conflicts.txt b/idea/testData/refactoring/safeDeleteMultiModule/byImplFun/conflicts.txt index a6c30c3d0ec..0f979ef2cfc 100644 --- a/idea/testData/refactoring/safeDeleteMultiModule/byImplFun/conflicts.txt +++ b/idea/testData/refactoring/safeDeleteMultiModule/byImplFun/conflicts.txt @@ -1 +1 @@ -function test.foo(Int) has 1 usage that is not safe to delete. \ No newline at end of file +function test.foo(Int) has 2 usages that are not safe to delete. \ No newline at end of file diff --git a/idea/testData/refactoring/safeDeleteMultiModule/byImplVal/conflicts.txt b/idea/testData/refactoring/safeDeleteMultiModule/byImplVal/conflicts.txt index d43eee6b09e..40a33e1d29a 100644 --- a/idea/testData/refactoring/safeDeleteMultiModule/byImplVal/conflicts.txt +++ b/idea/testData/refactoring/safeDeleteMultiModule/byImplVal/conflicts.txt @@ -1 +1 @@ -property test.foo has 1 usage that is not safe to delete. \ No newline at end of file +property test.foo has 2 usages that are not safe to delete. \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/findUsages/FindUsagesMultiModuleTest.kt b/idea/tests/org/jetbrains/kotlin/findUsages/FindUsagesMultiModuleTest.kt index a2085c51f8d..c3cf63ae968 100644 --- a/idea/tests/org/jetbrains/kotlin/findUsages/FindUsagesMultiModuleTest.kt +++ b/idea/tests/org/jetbrains/kotlin/findUsages/FindUsagesMultiModuleTest.kt @@ -22,11 +22,21 @@ import java.io.File class FindUsagesMultiModuleTest : AbstractFindUsagesMultiModuleTest() { + @Test + fun testFindCommonClassFromActual() { + doTest() + } + @Test fun testFindCommonFromActual() { doTest() } + @Test + fun testFindCommonPropertyFromActual() { + doTest() + } + @Test fun testFindImplFromHeader() { doTest() diff --git a/idea/tests/org/jetbrains/kotlin/findUsages/OptionsParser.kt b/idea/tests/org/jetbrains/kotlin/findUsages/OptionsParser.kt index e77f9f4e303..d751e201b9f 100644 --- a/idea/tests/org/jetbrains/kotlin/findUsages/OptionsParser.kt +++ b/idea/tests/org/jetbrains/kotlin/findUsages/OptionsParser.kt @@ -41,6 +41,7 @@ internal enum class OptionsParser { "derivedClasses" -> isDerivedClasses = true "functionUsages" -> isMethodsUsages = true "propertyUsages" -> isFieldsUsages = true + "expected" -> searchExpected = true else -> throw IllegalStateException("Invalid option: " + s) } } @@ -63,6 +64,10 @@ internal enum class OptionsParser { isIncludeOverloadUsages = true isUsages = true } + "expected" -> { + searchExpected = true + isUsages = true + } else -> throw IllegalStateException("Invalid option: " + s) } } @@ -80,6 +85,7 @@ internal enum class OptionsParser { "overrides" -> searchOverrides = true "skipRead" -> isReadAccess = false "skipWrite" -> isWriteAccess = false + "expected" -> searchExpected = true else -> throw IllegalStateException("Invalid option: " + s) } }