search for Kotlin convention usages of Java methods

#KT-5960 Fixed
This commit is contained in:
Dmitry Jemerov
2016-06-03 21:22:25 +02:00
parent 7e2ce2d4e0
commit 060c285715
8 changed files with 142 additions and 47 deletions
@@ -17,7 +17,6 @@
package org.jetbrains.kotlin.idea.search.ideaExtensions
import com.intellij.openapi.application.QueryExecutorBase
import com.intellij.openapi.progress.ProgressManager
import com.intellij.psi.*
import com.intellij.psi.impl.cache.CacheManager
import com.intellij.psi.search.*
@@ -30,7 +29,9 @@ import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
import org.jetbrains.kotlin.idea.search.KOTLIN_NAMED_ARGUMENT_SEARCH_CONTEXT
import org.jetbrains.kotlin.idea.search.allScope
import org.jetbrains.kotlin.idea.search.effectiveSearchScope
import org.jetbrains.kotlin.idea.search.usagesSearch.*
import org.jetbrains.kotlin.idea.search.usagesSearch.dataClassComponentFunction
import org.jetbrains.kotlin.idea.search.usagesSearch.getClassNameForCompanionObject
import org.jetbrains.kotlin.idea.search.usagesSearch.getSpecialNamesToSearch
import org.jetbrains.kotlin.idea.stubindex.KotlinSourceFilterScope
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.psi.*
@@ -84,7 +85,7 @@ class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, ReferencesSearc
val kotlinOptions = (queryParameters as? KotlinReferencesSearchParameters)?.kotlinOptions
?: KotlinReferencesSearchOptions.Empty
val resultProcessor = MyRequestResultProcessor(unwrappedElement, filter = refFilter, options = kotlinOptions)
val resultProcessor = KotlinRequestResultProcessor(unwrappedElement, filter = refFilter, options = kotlinOptions)
if (kotlinOptions.anyEnabled()) {
val name = runReadAction { unwrappedElement.name }
@@ -123,7 +124,7 @@ class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, ReferencesSearc
namedArgsScope = GlobalSearchScope.filesScope(project, filesWithFunctionName.asList())
}
val processor = MyRequestResultProcessor(parameter, filter = { it.isNamedArgumentReference() })
val processor = KotlinRequestResultProcessor(parameter, filter = { it.isNamedArgumentReference() })
queryParameters.optimizer.searchWord(parameterName,
namedArgsScope,
KOTLIN_NAMED_ARGUMENT_SEARCH_CONTEXT,
@@ -136,46 +137,6 @@ class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, ReferencesSearc
return this is KtSimpleNameReference && expression.parent is KtValueArgumentName
}
private class MyRequestResultProcessor(
private val unwrappedElement: PsiElement,
private val originalElement: PsiElement = unwrappedElement,
private val filter: (PsiReference) -> Boolean = { true },
private val options: KotlinReferencesSearchOptions = KotlinReferencesSearchOptions.Empty
) : RequestResultProcessor(unwrappedElement, originalElement, filter, options) {
private val referenceService = PsiReferenceService.getService()
override fun processTextOccurrence(element: PsiElement, offsetInElement: Int, consumer: Processor<PsiReference>): Boolean {
return referenceService.getReferences(element, PsiReferenceService.Hints.NO_HINTS).all { ref ->
ProgressManager.checkCanceled()
when {
!filter(ref) -> true
!ReferenceRange.containsOffsetInElement(ref, offsetInElement) -> true
!ref.isReferenceToTarget(unwrappedElement) -> true
else -> consumer.process(ref)
}
}
}
private fun PsiReference.isReferenceToTarget(element: PsiElement): Boolean {
if (isReferenceTo(element)) {
return true
}
if (originalElement is KtNamedDeclaration) {
if (options.acceptCallableOverrides && isCallableOverrideUsage(originalElement)) {
return true
}
if (options.acceptOverloads && isUsageInContainingDeclaration(originalElement)) {
return true
}
if (options.acceptExtensionsOfDeclarationClass && isExtensionOfDeclarationClassUsage(originalElement)) {
return true
}
}
return false
}
}
companion object {
fun processKtClassOrObject(element: KtClassOrObject, queryParameters: ReferencesSearch.SearchParameters) {
val className = element.name
@@ -323,9 +284,9 @@ class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, ReferencesSearc
val context = UsageSearchContext.IN_CODE + UsageSearchContext.IN_FOREIGN_LANGUAGES + UsageSearchContext.IN_COMMENTS
val kotlinOptions = (queryParameters as? KotlinReferencesSearchParameters)?.kotlinOptions
?: KotlinReferencesSearchOptions.Empty
val resultProcessor = MyRequestResultProcessor(element,
queryParameters.elementToSearch.namedUnwrappedElement ?: element,
options = kotlinOptions)
val resultProcessor = KotlinRequestResultProcessor(element,
queryParameters.elementToSearch.namedUnwrappedElement ?: element,
options = kotlinOptions)
queryParameters.optimizer.searchWord(name, scope, context.toShort(), true, element,
resultProcessor)
}
@@ -0,0 +1,69 @@
/*
* Copyright 2010-2016 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.search.ideaExtensions
import com.intellij.openapi.progress.ProgressManager
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiReference
import com.intellij.psi.PsiReferenceService
import com.intellij.psi.ReferenceRange
import com.intellij.psi.search.RequestResultProcessor
import com.intellij.util.Processor
import org.jetbrains.kotlin.idea.search.usagesSearch.isCallableOverrideUsage
import org.jetbrains.kotlin.idea.search.usagesSearch.isExtensionOfDeclarationClassUsage
import org.jetbrains.kotlin.idea.search.usagesSearch.isUsageInContainingDeclaration
import org.jetbrains.kotlin.psi.KtNamedDeclaration
class KotlinRequestResultProcessor(
private val unwrappedElement: PsiElement,
private val originalElement: PsiElement = unwrappedElement,
private val filter: (PsiReference) -> Boolean = { true },
private val options: KotlinReferencesSearchOptions = KotlinReferencesSearchOptions.Empty
) : RequestResultProcessor(unwrappedElement, originalElement, filter, options) {
private val referenceService = PsiReferenceService.getService()
override fun processTextOccurrence(element: PsiElement, offsetInElement: Int, consumer: Processor<PsiReference>): Boolean {
return referenceService.getReferences(element, PsiReferenceService.Hints.NO_HINTS).all { ref ->
ProgressManager.checkCanceled()
when {
!filter(ref) -> true
!ReferenceRange.containsOffsetInElement(ref, offsetInElement) -> true
!ref.isReferenceToTarget(unwrappedElement) -> true
else -> consumer.process(ref)
}
}
}
private fun PsiReference.isReferenceToTarget(element: PsiElement): Boolean {
if (isReferenceTo(element)) {
return true
}
if (originalElement is KtNamedDeclaration) {
if (options.acceptCallableOverrides && isCallableOverrideUsage(originalElement)) {
return true
}
if (options.acceptOverloads && isUsageInContainingDeclaration(originalElement)) {
return true
}
if (options.acceptExtensionsOfDeclarationClass && isExtensionOfDeclarationClassUsage(originalElement)) {
return true
}
}
return false
}
}
+1
View File
@@ -620,6 +620,7 @@
<methodReferencesSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinPropertyAccessorsReferenceSearcher"/>
<methodReferencesSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinConstructorDelegationCallReferenceSearcher"/>
<methodReferencesSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinOverridingMethodReferenceSearcher"/>
<methodReferencesSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinConventionMethodReferencesSearcher"/>
<readWriteAccessDetector implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReadWriteAccessDetector" id="kotlin"/>
@@ -0,0 +1,47 @@
/*
* Copyright 2010-2016 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.search.ideaExtensions
import com.intellij.openapi.application.QueryExecutorBase
import com.intellij.psi.PsiReference
import com.intellij.psi.search.UsageSearchContext
import com.intellij.psi.search.searches.MethodReferencesSearch
import com.intellij.util.Processor
import org.jetbrains.kotlin.idea.search.restrictToKotlinSources
import org.jetbrains.kotlin.idea.search.usagesSearch.getOperationSymbolsToSearch
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.lexer.KtSingleValueToken
import org.jetbrains.kotlin.name.Name
class KotlinConventionMethodReferencesSearcher() : QueryExecutorBase<PsiReference, MethodReferencesSearch.SearchParameters>(true) {
override fun processQuery(queryParameters: MethodReferencesSearch.SearchParameters, consumer: Processor<PsiReference>) {
val method = queryParameters.method
val name = runReadAction { method.name }
if (!Name.isValidIdentifier(name)) return
val operationSymbolsToSearch = Name.identifier(name).getOperationSymbolsToSearch()
val wordsToSearch = operationSymbolsToSearch.first.map { (it as KtSingleValueToken).value }
if (wordsToSearch.isEmpty()) return
val resultProcessor = KotlinRequestResultProcessor(method,
filter = { ref -> ref.javaClass == operationSymbolsToSearch.second })
wordsToSearch.forEach { word ->
queryParameters.optimizer.searchWord(word, queryParameters.effectiveSearchScope.restrictToKotlinSources(),
UsageSearchContext.IN_CODE, true, method,
resultProcessor)
}
}
}
@@ -0,0 +1,7 @@
// PSI_ELEMENT: com.intellij.psi.PsiMethod
// OPTIONS: usages
public class Small {
public boolean c<caret>ontains(String str) { // Call "Find usages" for this method
return true;
}
}
@@ -0,0 +1,3 @@
fun some(small: Small) {
"asdf" in small
}
@@ -0,0 +1 @@
Function call 2 "asdf" in small
@@ -1422,6 +1422,12 @@ public class FindUsagesTestGenerated extends AbstractFindUsagesTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/findUsages/java/findJavaMethodUsages"), Pattern.compile("^(.+)\\.0\\.java$"), true);
}
@TestMetadata("ConventionUsages.0.java")
public void testConventionUsages() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/findUsages/java/findJavaMethodUsages/ConventionUsages.0.java");
doTest(fileName);
}
@TestMetadata("JKMethodOverrides.0.java")
public void testJKMethodOverrides() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/findUsages/java/findJavaMethodUsages/JKMethodOverrides.0.java");