Implement search helpers for Kotlin declarations
This commit is contained in:
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2013 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.jet.plugin.findUsages
|
||||
|
||||
import com.intellij.psi.PsiClass
|
||||
import com.intellij.psi.PsiConstructorCall
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiMethod
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.jet.lang.psi.*
|
||||
import org.jetbrains.jet.lang.psi.psiUtil.*
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext
|
||||
import org.jetbrains.jet.lang.resolve.BindingContextUtils
|
||||
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache
|
||||
|
||||
fun PsiElement.isConstructorUsage(jetClassOrObject: JetClassOrObject): Boolean {
|
||||
fun getCallDescriptor(bindingContext: BindingContext): DeclarationDescriptor? {
|
||||
val constructorCalleeExpression = getParentByType(javaClass<JetConstructorCalleeExpression>())
|
||||
if (constructorCalleeExpression != null) {
|
||||
return bindingContext.get(BindingContext.REFERENCE_TARGET, constructorCalleeExpression.getConstructorReferenceExpression())
|
||||
}
|
||||
|
||||
val callExpression = getParentByType(javaClass<JetCallExpression>())
|
||||
if (callExpression != null) {
|
||||
val callee = callExpression.getCalleeExpression()
|
||||
if (callee is JetReferenceExpression) {
|
||||
return bindingContext.get(BindingContext.REFERENCE_TARGET, callee)
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
fun checkJavaUsage(): Boolean {
|
||||
val call = getParentByType(javaClass<PsiConstructorCall>())
|
||||
return call != null && call == getParent()
|
||||
&& call.resolveConstructor()?.getContainingClass()?.getNavigationElement() == jetClassOrObject
|
||||
}
|
||||
|
||||
fun checkKotlinUsage(): Boolean {
|
||||
val file = getContainingFile()
|
||||
if (file !is JetFile) return false
|
||||
|
||||
val bindingContext = AnalyzerFacadeWithCache.analyzeFileWithCache(file).getBindingContext()
|
||||
|
||||
val descriptor = getCallDescriptor(bindingContext)
|
||||
if (descriptor !is ConstructorDescriptor) return false
|
||||
|
||||
return BindingContextUtils.descriptorToDeclaration(bindingContext, descriptor.getContainingDeclaration()) == jetClassOrObject
|
||||
}
|
||||
|
||||
return checkJavaUsage() || checkKotlinUsage()
|
||||
}
|
||||
+2
-2
@@ -35,10 +35,10 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.asJava.LightClassUtil;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.plugin.findUsages.FindUsagesPackage;
|
||||
import org.jetbrains.jet.plugin.hierarchy.HierarchyUtils;
|
||||
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache;
|
||||
import org.jetbrains.jet.plugin.references.JetPsiReference;
|
||||
import org.jetbrains.jet.plugin.search.usagesSearch.UsagesSearchPackage;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
@@ -150,7 +150,7 @@ public abstract class KotlinCallerMethodsTreeStructure extends KotlinCallTreeStr
|
||||
new Condition<PsiReference>() {
|
||||
@Override
|
||||
public boolean value(PsiReference reference) {
|
||||
return FindUsagesPackage.isConstructorUsage(reference.getElement(), classOrObject);
|
||||
return UsagesSearchPackage.isConstructorUsage(reference, classOrObject);
|
||||
}
|
||||
},
|
||||
defaultQueryProcessor(descriptor, methodToDescriptorMap, false)
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Copyright 2010-2013 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.jet.plugin.search.usagesSearch
|
||||
|
||||
import com.intellij.psi.PsiReference
|
||||
import org.jetbrains.jet.lang.psi.JetClassOrObject
|
||||
import org.jetbrains.jet.lang.psi.psiUtil.getParentByType
|
||||
import org.jetbrains.jet.lang.psi.JetImportDirective
|
||||
import org.jetbrains.jet.plugin.search.usagesSearch.*
|
||||
import org.jetbrains.jet.plugin.search.usagesSearch.UsagesSearchFilter.*
|
||||
import org.jetbrains.jet.lang.psi.JetProperty
|
||||
import org.jetbrains.jet.lang.psi.JetNamedFunction
|
||||
import java.util.Collections
|
||||
import java.util.ArrayList
|
||||
import org.jetbrains.jet.lang.psi.JetNamedDeclaration
|
||||
import com.intellij.psi.PsiNamedElement
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import org.jetbrains.jet.asJava.LightClassUtil
|
||||
import com.intellij.psi.PsiMethod
|
||||
import com.intellij.util.Query
|
||||
import com.intellij.psi.search.SearchRequestCollector
|
||||
import org.jetbrains.jet.lang.psi.JetCallableDeclaration
|
||||
|
||||
val isTargetUsage = (PsiReference::isTargetUsage).searchFilter
|
||||
|
||||
fun JetProperty.names(readable: Boolean = true, writable: Boolean = true): List<String> {
|
||||
val name = getName()!!
|
||||
|
||||
if (isLocal()) return Collections.singletonList(name)
|
||||
|
||||
val lightMethods = LightClassUtil.getLightClassPropertyMethods(this)
|
||||
val getter = lightMethods.getGetter()
|
||||
val setter = lightMethods.getSetter()
|
||||
|
||||
val result = arrayListOf(name)
|
||||
if (readable && getter != null) result.add(getter.getName())
|
||||
if (writable && setter != null) result.add(setter.getName())
|
||||
return result
|
||||
}
|
||||
|
||||
public abstract class UsagesSearchHelper<T : PsiNamedElement> {
|
||||
protected open fun makeFilter(target: UsagesSearchTarget<T>): UsagesSearchFilter = isTargetUsage
|
||||
|
||||
protected open fun makeWordList(target: UsagesSearchTarget<T>): List<String> {
|
||||
return with(target) {
|
||||
val name = element.getName()
|
||||
|
||||
when {
|
||||
name == null -> Collections.emptyList<String>()
|
||||
element is JetProperty -> element.names()
|
||||
else -> Collections.singletonList(name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected open fun makeItemList(target: UsagesSearchTarget<T>): List<UsagesSearchRequestItem> =
|
||||
Collections.singletonList(newItem(target))
|
||||
|
||||
fun newItem(target: UsagesSearchTarget<T>): UsagesSearchRequestItem {
|
||||
return UsagesSearchRequestItem(target, makeWordList(target), makeFilter(target))
|
||||
}
|
||||
|
||||
fun newRequest(target: UsagesSearchTarget<T>): UsagesSearchRequest {
|
||||
return UsagesSearchRequest(target.element.getProject(), makeItemList(target))
|
||||
}
|
||||
}
|
||||
|
||||
object DefaultUsagesSearchHelper: UsagesSearchHelper<PsiNamedElement>()
|
||||
|
||||
val isNotImportUsage = !((PsiReference::isImportUsage).searchFilter)
|
||||
|
||||
open class DeclarationUsagesSearchHelper<T : PsiNamedElement> : UsagesSearchHelper<T>() {
|
||||
public var skipImports: Boolean = false
|
||||
|
||||
protected val isFilteredImport: UsagesSearchFilter
|
||||
get() = isNotImportUsage.ifOrTrue(skipImports)
|
||||
|
||||
override fun makeFilter(target: UsagesSearchTarget<T>): UsagesSearchFilter = isTargetUsage and isFilteredImport
|
||||
}
|
||||
|
||||
val isClassConstructorUsage = (PsiReference::isConstructorUsage).searchFilter
|
||||
|
||||
class ClassUsagesSearchHelper : DeclarationUsagesSearchHelper<JetClassOrObject>() {
|
||||
public var constructorUsages: Boolean = false
|
||||
public var nonConstructorUsages: Boolean = false
|
||||
|
||||
override fun makeFilter(target: UsagesSearchTarget<JetClassOrObject>): UsagesSearchFilter =
|
||||
super.makeFilter(target) and when {
|
||||
constructorUsages && !nonConstructorUsages -> isClassConstructorUsage
|
||||
!constructorUsages && nonConstructorUsages -> !isClassConstructorUsage
|
||||
!constructorUsages && !nonConstructorUsages -> False
|
||||
else -> True
|
||||
}
|
||||
}
|
||||
|
||||
class ClassDeclarationsUsagesSearchHelper : DeclarationUsagesSearchHelper<JetClassOrObject>() {
|
||||
public var functionUsages: Boolean = false
|
||||
public var propertyUsages: Boolean = false
|
||||
|
||||
override fun makeItemList(target: UsagesSearchTarget<JetClassOrObject>): List<UsagesSearchRequestItem> {
|
||||
val items = ArrayList<UsagesSearchRequestItem>()
|
||||
val declHelper = DeclarationUsagesSearchHelper<JetNamedDeclaration>(skipImports)
|
||||
|
||||
for (decl in target.element.getDeclarations()) {
|
||||
if ((decl is JetNamedFunction && functionUsages) || (decl is JetProperty && propertyUsages)) {
|
||||
items.add(declHelper.newItem(target.retarget(decl as JetNamedDeclaration)))
|
||||
}
|
||||
}
|
||||
|
||||
return items
|
||||
}
|
||||
}
|
||||
|
||||
val isOverrideUsage = (PsiReference::isCallableOverrideUsage).searchFilter
|
||||
|
||||
abstract class CallableUsagesSearchHelper<T: JetCallableDeclaration>: DeclarationUsagesSearchHelper<T>() {
|
||||
public var selfUsages: Boolean = true
|
||||
public var overrideUsages: Boolean = true
|
||||
|
||||
val isTargetOrOverrideUsage: UsagesSearchFilter
|
||||
get() = isTargetUsage.ifOrFalse(selfUsages) or isOverrideUsage.ifOrFalse(overrideUsages)
|
||||
}
|
||||
|
||||
val isOverloadUsage = (PsiReference::isUsageInContainingDeclaration).searchFilter
|
||||
val isExtensionUsage = (PsiReference::isExtensionOfDeclarationClassUsage).searchFilter
|
||||
|
||||
class FunctionUsagesSearchHelper() : CallableUsagesSearchHelper<JetNamedFunction>() {
|
||||
public var overloadUsages: Boolean = false
|
||||
public var extensionUsages: Boolean = false
|
||||
|
||||
override fun makeFilter(target: UsagesSearchTarget<JetNamedFunction>): UsagesSearchFilter {
|
||||
return (isTargetOrOverrideUsage
|
||||
or isOverloadUsage.ifOrFalse(overloadUsages)
|
||||
or isExtensionUsage.ifOrFalse(extensionUsages)) and isFilteredImport
|
||||
}
|
||||
}
|
||||
|
||||
val isPropertyReadOnlyUsage = (PsiReference::isPropertyReadOnlyUsage).searchFilter
|
||||
|
||||
class PropertyUsagesSearchHelper() : CallableUsagesSearchHelper<JetProperty>() {
|
||||
public var readUsages: Boolean = true
|
||||
public var writeUsages: Boolean = true
|
||||
|
||||
override fun makeWordList(target: UsagesSearchTarget<JetProperty>): List<String> {
|
||||
return target.element.names(readable = readUsages, writable = writeUsages)
|
||||
}
|
||||
|
||||
override fun makeFilter(target: UsagesSearchTarget<JetProperty>): UsagesSearchFilter {
|
||||
val readWriteUsage = when {
|
||||
readUsages && writeUsages -> True
|
||||
readUsages -> isPropertyReadOnlyUsage
|
||||
writeUsages -> !isPropertyReadOnlyUsage
|
||||
else -> False
|
||||
}
|
||||
return isTargetOrOverrideUsage and readWriteUsage and isFilteredImport
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright 2010-2013 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.jet.plugin.search.usagesSearch
|
||||
|
||||
import com.intellij.psi.PsiClass
|
||||
import com.intellij.psi.PsiConstructorCall
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiMethod
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.jet.lang.psi.*
|
||||
import org.jetbrains.jet.lang.psi.psiUtil.*
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext
|
||||
import org.jetbrains.jet.lang.resolve.BindingContextUtils
|
||||
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache
|
||||
import com.intellij.psi.PsiReference
|
||||
import org.jetbrains.jet.lang.resolve.java.jetAsJava.JetClsMethod
|
||||
import org.jetbrains.jet.lang.resolve.OverridingUtil
|
||||
import org.jetbrains.jet.plugin.references.JetPsiReference
|
||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils
|
||||
import org.jetbrains.jet.lang.descriptors.CallableDescriptor
|
||||
import org.jetbrains.jet.plugin.findUsages.JetUsageTypeProvider
|
||||
import org.jetbrains.jet.plugin.findUsages.JetUsageTypes
|
||||
import com.intellij.usages.impl.rules.UsageType
|
||||
import org.jetbrains.jet.asJava.LightClassUtil
|
||||
import org.jetbrains.jet.lang.resolve.java.JvmAbi
|
||||
import org.jetbrains.jet.codegen.PropertyCodegen
|
||||
|
||||
val PsiReference.navigationTarget: PsiElement?
|
||||
get() {
|
||||
val target = resolve()?.getNavigationElement()
|
||||
return if (target is JetPropertyAccessor) target.getParentByType(javaClass<JetProperty>()) else target
|
||||
}
|
||||
|
||||
val JetDeclaration.descriptor: DeclarationDescriptor?
|
||||
get() = AnalyzerFacadeWithCache.getContextForElement(this).get(BindingContext.DECLARATION_TO_DESCRIPTOR, this)
|
||||
|
||||
fun PsiReference.isTargetUsage(target: PsiElement): Boolean {
|
||||
return target.getNavigationElement() == navigationTarget
|
||||
}
|
||||
|
||||
fun PsiReference.checkUsageVsOriginalDescriptor(
|
||||
target: JetDeclaration, checker: (usageDescriptor: DeclarationDescriptor, targetDescriptor: DeclarationDescriptor) -> Boolean
|
||||
): Boolean {
|
||||
val refTarget = navigationTarget
|
||||
if (refTarget !is JetDeclaration) return false
|
||||
|
||||
val usageDescriptor = refTarget.descriptor
|
||||
val targetDescriptor = target.descriptor
|
||||
return usageDescriptor != null && targetDescriptor != null && checker(usageDescriptor, targetDescriptor)
|
||||
}
|
||||
|
||||
fun PsiReference.isImportUsage(): Boolean =
|
||||
getElement()!!.getParentByType(javaClass<JetImportDirective>()) != null
|
||||
|
||||
fun PsiReference.isConstructorUsage(jetClassOrObject: JetClassOrObject): Boolean = with (getElement()!!) {
|
||||
fun getCallDescriptor(bindingContext: BindingContext): DeclarationDescriptor? {
|
||||
val constructorCalleeExpression = getParentByType(javaClass<JetConstructorCalleeExpression>())
|
||||
if (constructorCalleeExpression != null) {
|
||||
return bindingContext.get(BindingContext.REFERENCE_TARGET, constructorCalleeExpression.getConstructorReferenceExpression())
|
||||
}
|
||||
|
||||
val callExpression = getParentByType(javaClass<JetCallExpression>())
|
||||
if (callExpression != null) {
|
||||
val callee = callExpression.getCalleeExpression()
|
||||
if (callee is JetReferenceExpression) {
|
||||
return bindingContext.get(BindingContext.REFERENCE_TARGET, callee)
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
fun checkJavaUsage(): Boolean {
|
||||
val call = getParentByType(javaClass<PsiConstructorCall>())
|
||||
return call != null && call == getParent()
|
||||
&& call.resolveConstructor()?.getContainingClass()?.getNavigationElement() == jetClassOrObject
|
||||
}
|
||||
|
||||
fun checkKotlinUsage(): Boolean {
|
||||
val file = getContainingFile()
|
||||
if (file !is JetFile) return false
|
||||
|
||||
val bindingContext = AnalyzerFacadeWithCache.analyzeFileWithCache(file).getBindingContext()
|
||||
|
||||
val descriptor = getCallDescriptor(bindingContext)
|
||||
if (descriptor !is ConstructorDescriptor) return false
|
||||
|
||||
return BindingContextUtils.descriptorToDeclaration(bindingContext, descriptor.getContainingDeclaration()) == jetClassOrObject
|
||||
}
|
||||
|
||||
checkJavaUsage() || checkKotlinUsage()
|
||||
}
|
||||
|
||||
fun PsiReference.isExtensionOfDeclarationClassUsage(declaration: JetNamedDeclaration): Boolean =
|
||||
checkUsageVsOriginalDescriptor(declaration) { (usageDescriptor, targetDescriptor) ->
|
||||
when {
|
||||
usageDescriptor == targetDescriptor -> false
|
||||
usageDescriptor !is FunctionDescriptor -> false
|
||||
else -> {
|
||||
val receiverDescriptor =
|
||||
usageDescriptor.getReceiverParameter()?.getType()?.getConstructor()?.getDeclarationDescriptor()
|
||||
val containingDescriptor = targetDescriptor.getContainingDeclaration()
|
||||
|
||||
containingDescriptor == receiverDescriptor
|
||||
|| (containingDescriptor is ClassDescriptor
|
||||
&& receiverDescriptor is ClassDescriptor
|
||||
&& DescriptorUtils.isSubclass(containingDescriptor, receiverDescriptor))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun PsiReference.isUsageInContainingDeclaration(declaration: JetNamedDeclaration): Boolean =
|
||||
checkUsageVsOriginalDescriptor(declaration) { (usageDescriptor, targetDescriptor) ->
|
||||
usageDescriptor != targetDescriptor
|
||||
&& usageDescriptor.getContainingDeclaration() == targetDescriptor.getContainingDeclaration()
|
||||
}
|
||||
|
||||
fun PsiReference.isCallableOverrideUsage(declaration: JetCallableDeclaration): Boolean =
|
||||
checkUsageVsOriginalDescriptor(declaration) { (usageDescriptor, targetDescriptor) ->
|
||||
usageDescriptor is CallableDescriptor && targetDescriptor is CallableDescriptor
|
||||
&& OverridingUtil.overrides(usageDescriptor, targetDescriptor)
|
||||
}
|
||||
|
||||
fun PsiReference.isPropertyReadOnlyUsage(): Boolean {
|
||||
if (this is JetPsiReference) {
|
||||
return JetUsageTypeProvider.getUsageType(getElement()) != UsageType.WRITE
|
||||
}
|
||||
|
||||
val refTarget = resolve()
|
||||
|
||||
if (refTarget is JetClsMethod) {
|
||||
val property = refTarget.getOrigin()?.getParentByType(javaClass<JetProperty>())
|
||||
return property != null && refTarget.getName() == PropertyCodegen.getterName(property.getNameAsName())
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
Reference in New Issue
Block a user