diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/psiUtil/jetPsiUtil.kt b/compiler/frontend/src/org/jetbrains/jet/lang/psi/psiUtil/jetPsiUtil.kt index b3eb96787f7..2da1f45892d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/psiUtil/jetPsiUtil.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/psiUtil/jetPsiUtil.kt @@ -18,6 +18,7 @@ package org.jetbrains.jet.lang.psi.psiUtil import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile +import com.intellij.psi.util.PsiTreeUtil fun PsiElement.getParentByTypeAndPredicate( parentClass : Class, strict : Boolean = false, predicate: (T) -> Boolean @@ -36,4 +37,21 @@ fun PsiElement.getParentByTypeAndPredicate( } return null +} + +fun PsiElement.getParentByType(parentClass : Class, strict : Boolean = false) : T? { + return PsiTreeUtil.getParentOfType(this, parentClass, strict) +} + +fun PsiElement?.isAncestor(element: PsiElement, strict: Boolean = false): Boolean { + return PsiTreeUtil.isAncestor(this, element, strict) +} + +fun T.getIfChildIsInBranch(element: PsiElement, branch: T.() -> PsiElement?): T? { + return if (branch().isAncestor(element)) this else null +} + +fun PsiElement.getParentByTypeAndBranch( + parentClass : Class, strict : Boolean = false, branch: T.() -> PsiElement?) : T? { + return getParentByType(parentClass, strict)?.getIfChildIsInBranch(this, branch) } \ No newline at end of file diff --git a/idea/src/org/jetbrains/jet/plugin/findUsages/JetUsageTypeProvider.java b/idea/src/org/jetbrains/jet/plugin/findUsages/JetUsageTypeProvider.java deleted file mode 100644 index b22a02abaab..00000000000 --- a/idea/src/org/jetbrains/jet/plugin/findUsages/JetUsageTypeProvider.java +++ /dev/null @@ -1,220 +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.PsiElement; -import com.intellij.psi.tree.IElementType; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.usages.UsageTarget; -import com.intellij.usages.impl.rules.UsageType; -import com.intellij.usages.impl.rules.UsageTypeProviderEx; -import jet.Function1; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.descriptors.*; -import org.jetbrains.jet.lang.psi.*; -import org.jetbrains.jet.lang.psi.psiUtil.PsiUtilPackage; -import org.jetbrains.jet.lang.resolve.BindingContext; -import org.jetbrains.jet.lexer.JetTokens; -import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache; - -public class JetUsageTypeProvider implements UsageTypeProviderEx { - private static final Function1 IS_ASSIGNMENT = new Function1() { - @Override - public Boolean invoke(@Nullable PsiElement input) { - return input != null && JetPsiUtil.isAssignment(input); - } - }; - - @Nullable - @Override - public UsageType getUsageType(PsiElement element) { - return getUsageType(element, UsageTarget.EMPTY_ARRAY); - } - - @Nullable - @Override - public UsageType getUsageType(PsiElement element, @NotNull UsageTarget[] targets) { - if (element == null) return null; - - UsageType usageType = getCommonUsageType(element); - if (usageType != null) return usageType; - - JetSimpleNameExpression reference = PsiTreeUtil.getParentOfType(element, JetSimpleNameExpression.class, false); - if (reference == null) return null; - - BindingContext bindingContext = - AnalyzerFacadeWithCache.analyzeFileWithCache((JetFile) element.getContainingFile()).getBindingContext(); - DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, reference); - - if (descriptor instanceof ClassifierDescriptor) { - return getClassUsageType(element); - } - if (descriptor instanceof VariableDescriptor) { - return getVariableUsageType(element); - } - if (descriptor instanceof FunctionDescriptor) { - return getFunctionUsageType(element, (FunctionDescriptor) descriptor); - } - - return null; - } - - private static UsageType getCommonUsageType(@NotNull PsiElement element) { - JetImportDirective importDirective = PsiTreeUtil.getParentOfType(element, JetImportDirective.class, false); - if (importDirective != null) return JetUsageTypes.IMPORT_DIRECTIVE; - - JetCallableReferenceExpression callableReference = - PsiTreeUtil.getParentOfType(element, JetCallableReferenceExpression.class, false); - if (callableReference != null && PsiTreeUtil.isAncestor(callableReference.getCallableReference(), element, false)) { - return JetUsageTypes.CALLABLE_REFERENCE; - } - - return null; - } - - @Nullable - private static UsageType getClassUsageType(@NotNull PsiElement element) { - JetTypeParameter typeParameter = PsiTreeUtil.getParentOfType(element, JetTypeParameter.class, false); - if (typeParameter != null && PsiTreeUtil.isAncestor(typeParameter.getExtendsBound(), element, false)) { - return JetUsageTypes.TYPE_CONSTRAINT; - } - - JetTypeConstraint typeConstraint = PsiTreeUtil.getParentOfType(element, JetTypeConstraint.class, false); - if (typeConstraint != null && PsiTreeUtil.isAncestor(typeConstraint.getBoundTypeReference(), element, false)) { - return JetUsageTypes.TYPE_CONSTRAINT; - } - - JetDelegationSpecifier delegationSpecifier = PsiTreeUtil.getParentOfType(element, JetDelegationSpecifier.class, false); - if (delegationSpecifier != null - && (delegationSpecifier == element || PsiTreeUtil.isAncestor(delegationSpecifier.getTypeReference(), element, false))) { - return JetUsageTypes.SUPER_TYPE; - } - - JetTypedef typedef = PsiTreeUtil.getParentOfType(element, JetTypedef.class, false); - if (typedef != null && PsiTreeUtil.isAncestor(typedef.getTypeReference(), element, false)) { - return JetUsageTypes.TYPE_DEFINITION; - } - - JetTypeProjection typeProjection = PsiTreeUtil.getParentOfType(element, JetTypeProjection.class, false); - if (typeProjection != null) return JetUsageTypes.TYPE_ARGUMENT; - - JetParameter parameter = PsiTreeUtil.getParentOfType(element, JetParameter.class, false); - if (parameter != null) { - if (PsiTreeUtil.isAncestor(parameter.getTypeReference(), element, false)) return JetUsageTypes.VALUE_PARAMETER_TYPE; - } - - JetProperty property = PsiTreeUtil.getParentOfType(element, JetProperty.class, false); - if (property != null) { - if (PsiTreeUtil.isAncestor(property.getTypeRef(), element, false)) { - return property.isLocal() ? JetUsageTypes.LOCAL_VARIABLE_TYPE : JetUsageTypes.NON_LOCAL_PROPERTY_TYPE; - } - if (PsiTreeUtil.isAncestor(property.getReceiverTypeRef(), element, false)) { - return JetUsageTypes.EXTENSION_RECEIVER_TYPE; - } - } - - JetFunction function = PsiTreeUtil.getParentOfType(element, JetFunction.class, false); - if (function != null) { - if (PsiTreeUtil.isAncestor(function.getReturnTypeRef(), element, false)) { - return JetUsageTypes.FUNCTION_RETURN_TYPE; - } - if (PsiTreeUtil.isAncestor(function.getReceiverTypeRef(), element, false)) { - return JetUsageTypes.EXTENSION_RECEIVER_TYPE; - } - } - - JetIsExpression isExpression = PsiTreeUtil.getParentOfType(element, JetIsExpression.class, false); - if (isExpression != null && PsiTreeUtil.isAncestor(isExpression.getTypeRef(), element, false)) { - return JetUsageTypes.IS; - } - - JetBinaryExpressionWithTypeRHS typeRHSExpression = - PsiTreeUtil.getParentOfType(element, JetBinaryExpressionWithTypeRHS.class, false); - if (typeRHSExpression != null && PsiTreeUtil.isAncestor(typeRHSExpression.getRight(), element, false)) { - IElementType opType = typeRHSExpression.getOperationReference().getReferencedNameElementType(); - if (opType == JetTokens.AS_KEYWORD || opType == JetTokens.AS_SAFE) return JetUsageTypes.AS; - } - - JetDotQualifiedExpression dotQualifiedExpression = PsiTreeUtil.getParentOfType(element, JetDotQualifiedExpression.class, false); - if (dotQualifiedExpression != null - && dotQualifiedExpression.getReceiverExpression() instanceof JetSimpleNameExpression - && PsiTreeUtil.isAncestor(dotQualifiedExpression.getReceiverExpression(), element, false)) { - - return JetUsageTypes.CLASS_OBJECT_ACCESS; - } - - JetSuperExpression superExpression = PsiTreeUtil.getParentOfType(element, JetSuperExpression.class, false); - if (superExpression != null && PsiTreeUtil.isAncestor(superExpression.getSuperTypeQualifier(), element, false)) { - return JetUsageTypes.SUPER_TYPE_QUALIFIER; - } - - return null; - } - - @Nullable - private static UsageType getFunctionUsageType(@NotNull PsiElement element, @NotNull FunctionDescriptor descriptor) { - if (descriptor instanceof ConstructorDescriptor) { - JetAnnotationEntry annotation = PsiTreeUtil.getParentOfType(element, JetAnnotationEntry.class, false); - if (annotation != null && PsiTreeUtil.isAncestor(annotation.getTypeReference(), element, false)) { - return JetUsageTypes.ANNOTATION_TYPE; - } - } - - JetCallExpression callExpression = PsiTreeUtil.getParentOfType(element, JetCallExpression.class, false); - if (callExpression != null - && callExpression.getCalleeExpression() instanceof JetSimpleNameExpression - && PsiTreeUtil.isAncestor(callExpression.getCalleeExpression(), element, false)) { - - return (descriptor instanceof ConstructorDescriptor) ? JetUsageTypes.INSTANTIATION : JetUsageTypes.FUNCTION_CALL; - } - - return null; - } - - @Nullable - private static UsageType getVariableUsageType(@NotNull PsiElement element) { - JetDotQualifiedExpression dotQualifiedExpression = PsiTreeUtil.getParentOfType(element, JetDotQualifiedExpression.class, false); - if (dotQualifiedExpression != null) { - if (PsiTreeUtil.isAncestor(dotQualifiedExpression.getReceiverExpression(), element, false)) { - return JetUsageTypes.RECEIVER; - } - - PsiElement parent = dotQualifiedExpression.getParent(); - if (parent instanceof JetDotQualifiedExpression - && PsiTreeUtil.isAncestor(((JetDotQualifiedExpression) parent).getReceiverExpression(), element, false)) { - return JetUsageTypes.RECEIVER; - } - - return JetUsageTypes.SELECTOR; - } - - JetBinaryExpression binaryExpression = - PsiUtilPackage.getParentByTypeAndPredicate(element, JetBinaryExpression.class, false, IS_ASSIGNMENT); - if (binaryExpression != null && PsiTreeUtil.isAncestor(binaryExpression.getLeft(), element, false)) { - return UsageType.WRITE; - } - - JetSimpleNameExpression simpleNameExpression = PsiTreeUtil.getParentOfType(element, JetSimpleNameExpression.class, false); - if (simpleNameExpression != null) { - return UsageType.READ; - } - - return null; - } -} - diff --git a/idea/src/org/jetbrains/jet/plugin/findUsages/JetUsageTypeProvider.kt b/idea/src/org/jetbrains/jet/plugin/findUsages/JetUsageTypeProvider.kt new file mode 100644 index 00000000000..4934e57adde --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/findUsages/JetUsageTypeProvider.kt @@ -0,0 +1,201 @@ +/* + * 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.PsiElement +import com.intellij.psi.tree.IElementType +import com.intellij.psi.util.PsiTreeUtil +import com.intellij.usages.UsageTarget +import com.intellij.usages.impl.rules.UsageType +import com.intellij.usages.impl.rules.UsageTypeProviderEx +import jet.Function1 +import org.jetbrains.annotations.Nullable +import org.jetbrains.jet.lang.descriptors.* +import org.jetbrains.jet.lang.psi.* +import org.jetbrains.jet.lang.psi.psiUtil.* +import org.jetbrains.jet.lang.resolve.BindingContext +import org.jetbrains.jet.lexer.JetTokens +import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache +import org.jetbrains.jet.plugin.JetBundle + +public class JetUsageTypeProvider() : UsageTypeProviderEx { + public override fun getUsageType(element: PsiElement?): UsageType? { + return getUsageType(element, UsageTarget.EMPTY_ARRAY) + } + + public override fun getUsageType(element: PsiElement?, targets: Array): UsageType? { + if (element == null) return null + + fun getCommonUsageType(): UsageType? { + return when { + element.getParentByType(javaClass()) != null -> + JetUsageTypes.IMPORT_DIRECTIVE + element.getParentByTypeAndBranch(javaClass()) { getCallableReference() } != null -> + JetUsageTypes.CALLABLE_REFERENCE + else -> null + } + } + + fun getClassUsageType(): UsageType? { + val property = element.getParentByType(javaClass()) + if (property != null) { + when { + property.getTypeRef().isAncestor(element) -> + return if (property.isLocal()) JetUsageTypes.LOCAL_VARIABLE_TYPE else JetUsageTypes.NON_LOCAL_PROPERTY_TYPE + + property.getReceiverTypeRef().isAncestor(element) -> + return JetUsageTypes.EXTENSION_RECEIVER_TYPE + } + } + + val function = element.getParentByType(javaClass()) + if (function != null) { + when { + function.getReturnTypeRef().isAncestor(element) -> + return JetUsageTypes.FUNCTION_RETURN_TYPE + function.getReceiverTypeRef().isAncestor(element) -> + return JetUsageTypes.EXTENSION_RECEIVER_TYPE + } + } + + return when { + element.getParentByTypeAndBranch(javaClass()) { getExtendsBound() } != null + || element.getParentByTypeAndBranch(javaClass()) { getBoundTypeReference() } != null -> + JetUsageTypes.TYPE_CONSTRAINT + + element is JetDelegationSpecifier + || element.getParentByTypeAndBranch(javaClass()) { getTypeReference() } != null -> + JetUsageTypes.SUPER_TYPE + + element.getParentByTypeAndBranch(javaClass()) { getTypeReference() } != null -> + JetUsageTypes.TYPE_DEFINITION + + element.getParentByType(javaClass()) != null -> + JetUsageTypes.TYPE_ARGUMENT + + element.getParentByTypeAndBranch(javaClass()) { getTypeReference() } != null -> + JetUsageTypes.VALUE_PARAMETER_TYPE + + element.getParentByTypeAndBranch(javaClass()) { getTypeRef() } != null -> + JetUsageTypes.IS + + with(element.getParentByTypeAndBranch(javaClass()) { getRight() }) { + val opType = this?.getOperationReference()?.getReferencedNameElementType() + opType == JetTokens.AS_KEYWORD || opType == JetTokens.AS_SAFE + } -> + JetUsageTypes.AS + + with(element.getParentByTypeAndBranch(javaClass()) { getReceiverExpression() }) { + this?.getReceiverExpression() is JetSimpleNameExpression + } -> + JetUsageTypes.CLASS_OBJECT_ACCESS + + element.getParentByTypeAndBranch(javaClass()) { getSuperTypeQualifier() } != null -> + JetUsageTypes.SUPER_TYPE_QUALIFIER + + else -> null + } + } + + fun getVariableUsageType(): UsageType? { + val dotQualifiedExpression = element.getParentByType(javaClass()) + + return if (dotQualifiedExpression != null) { + val parent = dotQualifiedExpression.getParent() + when { + dotQualifiedExpression.getReceiverExpression().isAncestor(element) -> + JetUsageTypes.RECEIVER + + parent is JetDotQualifiedExpression && parent.getReceiverExpression().isAncestor(element) -> + JetUsageTypes.RECEIVER + + else -> JetUsageTypes.SELECTOR + } + } + else { + when { + element.getParentByTypeAndPredicate( + javaClass(), false, { JetPsiUtil.isAssignment(it) } + )?.getLeft().isAncestor(element) -> + UsageType.WRITE + + element.getParentByType(javaClass()) != null -> + UsageType.READ + + else -> null + } + } + } + + fun getFunctionUsageType(descriptor: FunctionDescriptor): UsageType? { + return when { + descriptor is ConstructorDescriptor + && element.getParentByTypeAndBranch(javaClass()) { getTypeReference() } != null -> + JetUsageTypes.ANNOTATION_TYPE + + with(element.getParentByTypeAndBranch(javaClass()) { getCalleeExpression() }) { + this?.getCalleeExpression() is JetSimpleNameExpression + } -> + if (descriptor is ConstructorDescriptor) JetUsageTypes.INSTANTIATION else JetUsageTypes.FUNCTION_CALL + + else -> null + } + } + + val usageType = getCommonUsageType() + if (usageType != null) return usageType + + val reference = element.getParentByType(javaClass()) + if (reference == null) return null + + val file = element.getContainingFile() + if (file == null) return null + + val bindingContext = AnalyzerFacadeWithCache.analyzeFileWithCache(file as JetFile).getBindingContext() + val descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, reference) + + return when (descriptor) { + is ClassifierDescriptor -> getClassUsageType() + is VariableDescriptor -> getVariableUsageType() + is FunctionDescriptor -> getFunctionUsageType(descriptor) + else -> null + } + } +} + +object JetUsageTypes { + val ANNOTATION_TYPE = UsageType(JetBundle.message("usageType.annotation.type")) + val TYPE_CONSTRAINT = UsageType(JetBundle.message("usageType.type.constraint")) + val TYPE_ARGUMENT = UsageType(JetBundle.message("usageType.type.argument")) + val VALUE_PARAMETER_TYPE = UsageType(JetBundle.message("usageType.value.parameter.type")) + val NON_LOCAL_PROPERTY_TYPE = UsageType(JetBundle.message("usageType.nonLocal.property.type")) + val LOCAL_VARIABLE_TYPE = UsageType(JetBundle.message("usageType.local.variable.type")) + val FUNCTION_RETURN_TYPE = UsageType(JetBundle.message("usageType.function.return.type")) + val SUPER_TYPE = UsageType(JetBundle.message("usageType.superType")) + val TYPE_DEFINITION = UsageType(JetBundle.message("usageType.type.definition")) + val AS = UsageType(JetBundle.message("usageType.as")) + val IS = UsageType(JetBundle.message("usageType.is")) + val CLASS_OBJECT_ACCESS = UsageType(JetBundle.message("usageType.class.object")) + val EXTENSION_RECEIVER_TYPE = UsageType(JetBundle.message("usageType.extension.receiver.type")) + val SUPER_TYPE_QUALIFIER = UsageType(JetBundle.message("usageType.super.type.qualifier")) + val INSTANTIATION = UsageType(JetBundle.message("usageType.instantiation")) + val FUNCTION_CALL = UsageType(JetBundle.message("usageType.function.call")) + val RECEIVER = UsageType(JetBundle.message("usageType.receiver")) + val SELECTOR = UsageType(JetBundle.message("usageType.selector")) + val IMPORT_DIRECTIVE = UsageType(JetBundle.message("usageType.import")) + val CALLABLE_REFERENCE = UsageType(JetBundle.message("usageType.callable.reference")) +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/jet/plugin/findUsages/JetUsageTypes.java b/idea/src/org/jetbrains/jet/plugin/findUsages/JetUsageTypes.java deleted file mode 100644 index 4699d618bf8..00000000000 --- a/idea/src/org/jetbrains/jet/plugin/findUsages/JetUsageTypes.java +++ /dev/null @@ -1,53 +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.usages.impl.rules.UsageType; -import org.jetbrains.jet.plugin.JetBundle; - -public class JetUsageTypes { - private JetUsageTypes() { - } - - // Type-related usages - public static final UsageType ANNOTATION_TYPE = new UsageType(JetBundle.message("usageType.annotation.type")); - public static final UsageType TYPE_CONSTRAINT = new UsageType(JetBundle.message("usageType.type.constraint")); - public static final UsageType TYPE_ARGUMENT = new UsageType(JetBundle.message("usageType.type.argument")); - public static final UsageType VALUE_PARAMETER_TYPE = new UsageType(JetBundle.message("usageType.value.parameter.type")); - public static final UsageType NON_LOCAL_PROPERTY_TYPE = new UsageType(JetBundle.message("usageType.nonLocal.property.type")); - public static final UsageType LOCAL_VARIABLE_TYPE = new UsageType(JetBundle.message("usageType.local.variable.type")); - public static final UsageType FUNCTION_RETURN_TYPE = new UsageType(JetBundle.message("usageType.function.return.type")); - public static final UsageType SUPER_TYPE = new UsageType(JetBundle.message("usageType.superType")); - public static final UsageType TYPE_DEFINITION = new UsageType(JetBundle.message("usageType.type.definition")); - public static final UsageType AS = new UsageType(JetBundle.message("usageType.as")); - public static final UsageType IS = new UsageType(JetBundle.message("usageType.is")); - public static final UsageType CLASS_OBJECT_ACCESS = new UsageType(JetBundle.message("usageType.class.object")); - public static final UsageType EXTENSION_RECEIVER_TYPE = new UsageType(JetBundle.message("usageType.extension.receiver.type")); - public static final UsageType SUPER_TYPE_QUALIFIER = new UsageType(JetBundle.message("usageType.super.type.qualifier")); - - // Function-related usages - public static final UsageType INSTANTIATION = new UsageType(JetBundle.message("usageType.instantiation")); - public static final UsageType FUNCTION_CALL = new UsageType(JetBundle.message("usageType.function.call")); - - // Value-related usages - public static final UsageType RECEIVER = new UsageType(JetBundle.message("usageType.receiver")); - public static final UsageType SELECTOR = new UsageType(JetBundle.message("usageType.selector")); - - // Miscellaneous usages - public static final UsageType IMPORT_DIRECTIVE = new UsageType(JetBundle.message("usageType.import")); - public static final UsageType CALLABLE_REFERENCE = new UsageType(JetBundle.message("usageType.callable.reference")); -}