diff --git a/idea/src/org/jetbrains/jet/plugin/findUsages/utils.kt b/idea/src/org/jetbrains/jet/plugin/findUsages/utils.kt deleted file mode 100644 index 36ff34f0d81..00000000000 --- a/idea/src/org/jetbrains/jet/plugin/findUsages/utils.kt +++ /dev/null @@ -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()) - if (constructorCalleeExpression != null) { - return bindingContext.get(BindingContext.REFERENCE_TARGET, constructorCalleeExpression.getConstructorReferenceExpression()) - } - - val callExpression = getParentByType(javaClass()) - 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()) - 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() -} diff --git a/idea/src/org/jetbrains/jet/plugin/hierarchy/calls/KotlinCallerMethodsTreeStructure.java b/idea/src/org/jetbrains/jet/plugin/hierarchy/calls/KotlinCallerMethodsTreeStructure.java index e98971bd5b2..810861a128d 100644 --- a/idea/src/org/jetbrains/jet/plugin/hierarchy/calls/KotlinCallerMethodsTreeStructure.java +++ b/idea/src/org/jetbrains/jet/plugin/hierarchy/calls/KotlinCallerMethodsTreeStructure.java @@ -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() { @Override public boolean value(PsiReference reference) { - return FindUsagesPackage.isConstructorUsage(reference.getElement(), classOrObject); + return UsagesSearchPackage.isConstructorUsage(reference, classOrObject); } }, defaultQueryProcessor(descriptor, methodToDescriptorMap, false) diff --git a/idea/src/org/jetbrains/jet/plugin/search/usagesSearch/searchHelpers.kt b/idea/src/org/jetbrains/jet/plugin/search/usagesSearch/searchHelpers.kt new file mode 100644 index 00000000000..e4175051a90 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/search/usagesSearch/searchHelpers.kt @@ -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 { + 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 { + protected open fun makeFilter(target: UsagesSearchTarget): UsagesSearchFilter = isTargetUsage + + protected open fun makeWordList(target: UsagesSearchTarget): List { + return with(target) { + val name = element.getName() + + when { + name == null -> Collections.emptyList() + element is JetProperty -> element.names() + else -> Collections.singletonList(name) + } + } + } + + + protected open fun makeItemList(target: UsagesSearchTarget): List = + Collections.singletonList(newItem(target)) + + fun newItem(target: UsagesSearchTarget): UsagesSearchRequestItem { + return UsagesSearchRequestItem(target, makeWordList(target), makeFilter(target)) + } + + fun newRequest(target: UsagesSearchTarget): UsagesSearchRequest { + return UsagesSearchRequest(target.element.getProject(), makeItemList(target)) + } +} + +object DefaultUsagesSearchHelper: UsagesSearchHelper() + +val isNotImportUsage = !((PsiReference::isImportUsage).searchFilter) + +open class DeclarationUsagesSearchHelper : UsagesSearchHelper() { + public var skipImports: Boolean = false + + protected val isFilteredImport: UsagesSearchFilter + get() = isNotImportUsage.ifOrTrue(skipImports) + + override fun makeFilter(target: UsagesSearchTarget): UsagesSearchFilter = isTargetUsage and isFilteredImport +} + +val isClassConstructorUsage = (PsiReference::isConstructorUsage).searchFilter + +class ClassUsagesSearchHelper : DeclarationUsagesSearchHelper() { + public var constructorUsages: Boolean = false + public var nonConstructorUsages: Boolean = false + + override fun makeFilter(target: UsagesSearchTarget): UsagesSearchFilter = + super.makeFilter(target) and when { + constructorUsages && !nonConstructorUsages -> isClassConstructorUsage + !constructorUsages && nonConstructorUsages -> !isClassConstructorUsage + !constructorUsages && !nonConstructorUsages -> False + else -> True + } +} + +class ClassDeclarationsUsagesSearchHelper : DeclarationUsagesSearchHelper() { + public var functionUsages: Boolean = false + public var propertyUsages: Boolean = false + + override fun makeItemList(target: UsagesSearchTarget): List { + val items = ArrayList() + val declHelper = DeclarationUsagesSearchHelper(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: DeclarationUsagesSearchHelper() { + 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() { + public var overloadUsages: Boolean = false + public var extensionUsages: Boolean = false + + override fun makeFilter(target: UsagesSearchTarget): UsagesSearchFilter { + return (isTargetOrOverrideUsage + or isOverloadUsage.ifOrFalse(overloadUsages) + or isExtensionUsage.ifOrFalse(extensionUsages)) and isFilteredImport + } +} + +val isPropertyReadOnlyUsage = (PsiReference::isPropertyReadOnlyUsage).searchFilter + +class PropertyUsagesSearchHelper() : CallableUsagesSearchHelper() { + public var readUsages: Boolean = true + public var writeUsages: Boolean = true + + override fun makeWordList(target: UsagesSearchTarget): List { + return target.element.names(readable = readUsages, writable = writeUsages) + } + + override fun makeFilter(target: UsagesSearchTarget): UsagesSearchFilter { + val readWriteUsage = when { + readUsages && writeUsages -> True + readUsages -> isPropertyReadOnlyUsage + writeUsages -> !isPropertyReadOnlyUsage + else -> False + } + return isTargetOrOverrideUsage and readWriteUsage and isFilteredImport + } +} diff --git a/idea/src/org/jetbrains/jet/plugin/search/usagesSearch/utils.kt b/idea/src/org/jetbrains/jet/plugin/search/usagesSearch/utils.kt new file mode 100644 index 00000000000..089cb69314f --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/search/usagesSearch/utils.kt @@ -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()) 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()) != null + +fun PsiReference.isConstructorUsage(jetClassOrObject: JetClassOrObject): Boolean = with (getElement()!!) { + fun getCallDescriptor(bindingContext: BindingContext): DeclarationDescriptor? { + val constructorCalleeExpression = getParentByType(javaClass()) + if (constructorCalleeExpression != null) { + return bindingContext.get(BindingContext.REFERENCE_TARGET, constructorCalleeExpression.getConstructorReferenceExpression()) + } + + val callExpression = getParentByType(javaClass()) + 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()) + 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()) + return property != null && refTarget.getName() == PropertyCodegen.getterName(property.getNameAsName()) + } + + return false +} \ No newline at end of file