diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml
index a2c7b3152d6..206ae2c5e69 100644
--- a/idea/src/META-INF/plugin.xml
+++ b/idea/src/META-INF/plugin.xml
@@ -226,6 +226,7 @@
order="first"/>
+
diff --git a/idea/src/org/jetbrains/jet/plugin/JetBundle.properties b/idea/src/org/jetbrains/jet/plugin/JetBundle.properties
index 3fd4c5848b8..47bb855cc04 100644
--- a/idea/src/org/jetbrains/jet/plugin/JetBundle.properties
+++ b/idea/src/org/jetbrains/jet/plugin/JetBundle.properties
@@ -232,4 +232,25 @@ add.function.to.type.action.type.chooser=Choose type...
remove.expression = Remove ''{0}''
unwrap.expression = Unwrap ''{0}''
remove.else = Remove else in ''{0}''
-unwrap.else = Unwrap else in ''{0}''
\ No newline at end of file
+unwrap.else = Unwrap else in ''{0}''
+
+usageType.annotation.type = Annotation
+usageType.import = Import directive
+usageType.callable.reference = Callable reference
+usageType.type.constraint = Type constraint
+usageType.type.argument = Type argument
+usageType.value.parameter.type = Parameter type
+usageType.nonLocal.property.type = Class/object property type
+usageType.local.variable.type = Local variable type
+usageType.function.return.type = Function return types
+usageType.superType = Supertype
+usageType.type.definition = Type definition
+usageType.is = Target type of 'is' operation
+usageType.as = Target type of 'as' operation
+usageType.class.object = Nested class/object
+usageType.instantiation = Instantiation
+usageType.function.call = Function call
+usageType.extension.receiver.type = Extension receiver type
+usageType.super.type.qualifier = Super type qualifier
+usageType.receiver = Receiver
+usageType.selector = Selector
\ 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
new file mode 100644
index 00000000000..2b433894130
--- /dev/null
+++ b/idea/src/org/jetbrains/jet/plugin/findUsages/JetUsageTypeProvider.java
@@ -0,0 +1,219 @@
+/*
+ * 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.google.common.base.Predicate;
+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 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.resolve.BindingContext;
+import org.jetbrains.jet.lexer.JetTokens;
+import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache;
+
+public class JetUsageTypeProvider implements UsageTypeProviderEx {
+ private static final Predicate IS_ASSIGNMENT = new Predicate() {
+ @Override
+ public boolean apply(@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 =
+ (JetBinaryExpression) JetPsiUtil.getParentByTypeAndPredicate(element, JetBinaryExpression.class, IS_ASSIGNMENT, false);
+ 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/JetUsageTypes.java b/idea/src/org/jetbrains/jet/plugin/findUsages/JetUsageTypes.java
new file mode 100644
index 00000000000..4699d618bf8
--- /dev/null
+++ b/idea/src/org/jetbrains/jet/plugin/findUsages/JetUsageTypes.java
@@ -0,0 +1,53 @@
+/*
+ * 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"));
+}
diff --git a/idea/src/org/jetbrains/jet/plugin/search/KotlinReferencesSearcher.java b/idea/src/org/jetbrains/jet/plugin/search/KotlinReferencesSearcher.java
index a1d59dd58f8..dcd74e77463 100644
--- a/idea/src/org/jetbrains/jet/plugin/search/KotlinReferencesSearcher.java
+++ b/idea/src/org/jetbrains/jet/plugin/search/KotlinReferencesSearcher.java
@@ -27,26 +27,33 @@ import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.util.Processor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.asJava.LightClassUtil;
-import org.jetbrains.jet.lang.psi.JetClass;
-import org.jetbrains.jet.lang.psi.JetNamedFunction;
+import org.jetbrains.jet.lang.psi.*;
public class KotlinReferencesSearcher extends QueryExecutorBase {
+ public static void processJetClassOrObject(
+ final @NotNull JetClassOrObject element, @NotNull ReferencesSearch.SearchParameters queryParameters
+ ) {
+ String className = element.getName();
+ if (className != null) {
+ PsiClass lightClass = ApplicationManager.getApplication().runReadAction(new Computable() {
+ @Override
+ public PsiClass compute() {
+ return LightClassUtil.getPsiClass(element);
+ }
+ });
+ if (lightClass != null) {
+ queryParameters.getOptimizer().searchWord(className, queryParameters.getEffectiveSearchScope(), true, lightClass);
+ }
+ }
+ }
+
+
+
@Override
public void processQuery(@NotNull ReferencesSearch.SearchParameters queryParameters, @NotNull Processor consumer) {
- final PsiElement element = queryParameters.getElementToSearch();
+ PsiElement element = queryParameters.getElementToSearch();
if (element instanceof JetClass) {
- String className = ((JetClass) element).getName();
- if (className != null) {
- PsiClass lightClass = ApplicationManager.getApplication().runReadAction(new Computable() {
- @Override
- public PsiClass compute() {
- return LightClassUtil.getPsiClass((JetClass) element);
- }
- });
- if (lightClass != null) {
- queryParameters.getOptimizer().searchWord(className, queryParameters.getEffectiveSearchScope(), true, lightClass);
- }
- }
+ processJetClassOrObject((JetClass) element, queryParameters);
}
else if (element instanceof JetNamedFunction) {
final JetNamedFunction function = (JetNamedFunction) element;
@@ -58,10 +65,33 @@ public class KotlinReferencesSearcher extends QueryExecutorBase() {
+ @Override
+ public LightClassUtil.PropertyAccessorsPsiMethods compute() {
+ return LightClassUtil.getLightClassPropertyMethods(property);
+ }
+ });
+
+ searchMethod(queryParameters, propertyMethods.getGetter());
+ searchMethod(queryParameters, propertyMethods.getSetter());
+ }
+ else if (element instanceof JetObjectDeclarationName) {
+ PsiElement parent = element.getParent();
+ if (parent instanceof JetObjectDeclaration) {
+ processJetClassOrObject((JetObjectDeclaration)parent, queryParameters);
}
}
}
+
+ private static void searchMethod(ReferencesSearch.SearchParameters queryParameters, PsiMethod method) {
+ if (method != null) {
+ queryParameters.getOptimizer().searchWord(method.getName(), queryParameters.getEffectiveSearchScope(), true, method);
+ }
+ }
}
diff --git a/idea/testData/findUsages/findClassUsages/Client.java b/idea/testData/findUsages/findClassUsages/javaUsages/Client.java
similarity index 100%
rename from idea/testData/findUsages/findClassUsages/Client.java
rename to idea/testData/findUsages/findClassUsages/javaUsages/Client.java
diff --git a/idea/testData/findUsages/findClassUsages/Server.kt b/idea/testData/findUsages/findClassUsages/javaUsages/Server.kt
similarity index 100%
rename from idea/testData/findUsages/findClassUsages/Server.kt
rename to idea/testData/findUsages/findClassUsages/javaUsages/Server.kt
diff --git a/idea/testData/findUsages/findClassUsages/kotlinUsages1/Client.kt b/idea/testData/findUsages/findClassUsages/kotlinUsages1/Client.kt
new file mode 100644
index 00000000000..b24ac3812cf
--- /dev/null
+++ b/idea/testData/findUsages/findClassUsages/kotlinUsages1/Client.kt
@@ -0,0 +1,34 @@
+package client
+
+import server.Server
+
+class Client: Server {
+ var nextServer: Server? = null
+ val name = Server.NAME
+
+ fun foo(s: Server) {
+ val server: Server = s
+ println("Server: $server")
+ }
+
+ fun getNextServer(): Server? {
+ return nextServer
+ }
+
+ override fun work() {
+ super.work()
+ println("Client")
+ }
+}
+
+fun Client.bar(s: Server) {
+ foo(s)
+}
+
+fun Client.hasNextServer(): Boolean {
+ return getNextServer() != null
+}
+
+fun Any.asServer(): Server? {
+ return if (this is Server) this as Server else null
+}
\ No newline at end of file
diff --git a/idea/testData/findUsages/findClassUsages/kotlinUsages1/Server.kt b/idea/testData/findUsages/findClassUsages/kotlinUsages1/Server.kt
new file mode 100644
index 00000000000..e8f74cc9821
--- /dev/null
+++ b/idea/testData/findUsages/findClassUsages/kotlinUsages1/Server.kt
@@ -0,0 +1,11 @@
+package server
+
+open class Server {
+ class object {
+ val NAME = "Server"
+ }
+
+ open fun work() {
+ println("Server")
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/findUsages/findClassUsages/kotlinUsages2/Client.kt b/idea/testData/findUsages/findClassUsages/kotlinUsages2/Client.kt
new file mode 100644
index 00000000000..8511a3a9e92
--- /dev/null
+++ b/idea/testData/findUsages/findClassUsages/kotlinUsages2/Client.kt
@@ -0,0 +1,8 @@
+package client
+
+import server.X
+
+X("")
+class Client {
+
+}
\ No newline at end of file
diff --git a/idea/testData/findUsages/findClassUsages/kotlinUsages2/Server.kt b/idea/testData/findUsages/findClassUsages/kotlinUsages2/Server.kt
new file mode 100644
index 00000000000..92281e3ae02
--- /dev/null
+++ b/idea/testData/findUsages/findClassUsages/kotlinUsages2/Server.kt
@@ -0,0 +1,3 @@
+package server
+
+annotation class X(val x: String)
\ No newline at end of file
diff --git a/idea/testData/findUsages/findClassUsages/kotlinUsages3/Client.kt b/idea/testData/findUsages/findClassUsages/kotlinUsages3/Client.kt
new file mode 100644
index 00000000000..92d7b496461
--- /dev/null
+++ b/idea/testData/findUsages/findClassUsages/kotlinUsages3/Client.kt
@@ -0,0 +1,9 @@
+package client
+
+import server.Data
+
+class Client where X: Data {
+
+}
+
+val c = Client()
\ No newline at end of file
diff --git a/idea/testData/findUsages/findClassUsages/kotlinUsages3/Server.kt b/idea/testData/findUsages/findClassUsages/kotlinUsages3/Server.kt
new file mode 100644
index 00000000000..2b4068b1e88
--- /dev/null
+++ b/idea/testData/findUsages/findClassUsages/kotlinUsages3/Server.kt
@@ -0,0 +1,3 @@
+package server
+
+data class Data
\ No newline at end of file
diff --git a/idea/testData/findUsages/findMethodUsages/Client.java b/idea/testData/findUsages/findMethodUsages/javaUsages/Client.java
similarity index 100%
rename from idea/testData/findUsages/findMethodUsages/Client.java
rename to idea/testData/findUsages/findMethodUsages/javaUsages/Client.java
diff --git a/idea/testData/findUsages/findMethodUsages/Server.kt b/idea/testData/findUsages/findMethodUsages/javaUsages/Server.kt
similarity index 100%
rename from idea/testData/findUsages/findMethodUsages/Server.kt
rename to idea/testData/findUsages/findMethodUsages/javaUsages/Server.kt
diff --git a/idea/testData/findUsages/findMethodUsages/kotlinUsages/Client.kt b/idea/testData/findUsages/findMethodUsages/kotlinUsages/Client.kt
new file mode 100644
index 00000000000..9bd981a0c77
--- /dev/null
+++ b/idea/testData/findUsages/findMethodUsages/kotlinUsages/Client.kt
@@ -0,0 +1,12 @@
+package client
+
+import server.processRequest
+
+class Client {
+ val methodRef = ::processRequest()
+
+ fun doProcessRequest() {
+ println("Process...")
+ processRequest()
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/findUsages/findMethodUsages/kotlinUsages/Server.kt b/idea/testData/findUsages/findMethodUsages/kotlinUsages/Server.kt
new file mode 100644
index 00000000000..4c303b09795
--- /dev/null
+++ b/idea/testData/findUsages/findMethodUsages/kotlinUsages/Server.kt
@@ -0,0 +1,4 @@
+package server;
+
+fun processRequest() = "foo"
+
diff --git a/idea/testData/findUsages/findObjectUsages/javaUsages/Client.java b/idea/testData/findUsages/findObjectUsages/javaUsages/Client.java
new file mode 100644
index 00000000000..b896d9becc3
--- /dev/null
+++ b/idea/testData/findUsages/findObjectUsages/javaUsages/Client.java
@@ -0,0 +1,9 @@
+package client;
+
+import server.O
+
+class Client {
+ fun fooBar() {
+ println("foo = " + O.instance$.getFoo())
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/findUsages/findObjectUsages/javaUsages/Server.kt b/idea/testData/findUsages/findObjectUsages/javaUsages/Server.kt
new file mode 100644
index 00000000000..52c87b49e49
--- /dev/null
+++ b/idea/testData/findUsages/findObjectUsages/javaUsages/Server.kt
@@ -0,0 +1,6 @@
+package server;
+
+object O {
+ var foo: String = "foo"
+}
+
diff --git a/idea/testData/findUsages/findObjectUsages/kotlinUsages/Client.kt b/idea/testData/findUsages/findObjectUsages/kotlinUsages/Client.kt
new file mode 100644
index 00000000000..7b0126d1a91
--- /dev/null
+++ b/idea/testData/findUsages/findObjectUsages/kotlinUsages/Client.kt
@@ -0,0 +1,11 @@
+package client
+
+import server.O
+
+class Client {
+ fun fooBar() {
+ println("foo = ${O.foo}")
+ val obj = O
+ println("length: ${obj.foo.length()}")
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/findUsages/findObjectUsages/kotlinUsages/Server.kt b/idea/testData/findUsages/findObjectUsages/kotlinUsages/Server.kt
new file mode 100644
index 00000000000..52c87b49e49
--- /dev/null
+++ b/idea/testData/findUsages/findObjectUsages/kotlinUsages/Server.kt
@@ -0,0 +1,6 @@
+package server;
+
+object O {
+ var foo: String = "foo"
+}
+
diff --git a/idea/testData/findUsages/findPropertyUsages/javaUsages/Client.java b/idea/testData/findUsages/findPropertyUsages/javaUsages/Client.java
new file mode 100644
index 00000000000..b896d9becc3
--- /dev/null
+++ b/idea/testData/findUsages/findPropertyUsages/javaUsages/Client.java
@@ -0,0 +1,9 @@
+package client;
+
+import server.O
+
+class Client {
+ fun fooBar() {
+ println("foo = " + O.instance$.getFoo())
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/findUsages/findPropertyUsages/javaUsages/Server.kt b/idea/testData/findUsages/findPropertyUsages/javaUsages/Server.kt
new file mode 100644
index 00000000000..388e800f3d2
--- /dev/null
+++ b/idea/testData/findUsages/findPropertyUsages/javaUsages/Server.kt
@@ -0,0 +1,6 @@
+package server;
+
+object O {
+ var foo: String = "foo"
+}
+
diff --git a/idea/testData/findUsages/findPropertyUsages/kotlinUsages/Client.kt b/idea/testData/findUsages/findPropertyUsages/kotlinUsages/Client.kt
new file mode 100644
index 00000000000..4d9a435b595
--- /dev/null
+++ b/idea/testData/findUsages/findPropertyUsages/kotlinUsages/Client.kt
@@ -0,0 +1,10 @@
+package client
+
+import server.foo
+
+class Client {
+ fun fooBar() {
+ println("foo = ${server.foo}")
+ println("length: ${server.foo.length()}")
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/findUsages/findPropertyUsages/kotlinUsages/Server.kt b/idea/testData/findUsages/findPropertyUsages/kotlinUsages/Server.kt
new file mode 100644
index 00000000000..179159c259c
--- /dev/null
+++ b/idea/testData/findUsages/findPropertyUsages/kotlinUsages/Server.kt
@@ -0,0 +1,4 @@
+package server;
+
+var foo: String = "foo"
+
diff --git a/idea/tests/org/jetbrains/jet/findUsages/JetFindUsagesTest.java b/idea/tests/org/jetbrains/jet/findUsages/JetFindUsagesTest.java
index 5473b55c665..33e8c702c07 100644
--- a/idea/tests/org/jetbrains/jet/findUsages/JetFindUsagesTest.java
+++ b/idea/tests/org/jetbrains/jet/findUsages/JetFindUsagesTest.java
@@ -22,18 +22,24 @@ import com.google.common.base.Predicates;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import com.google.common.collect.Ordering;
+import com.intellij.openapi.extensions.Extensions;
+import com.intellij.psi.PsiComment;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.testFramework.LightProjectDescriptor;
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
import com.intellij.usageView.UsageInfo;
import com.intellij.usages.UsageInfo2UsageAdapter;
+import com.intellij.usages.impl.rules.UsageType;
+import com.intellij.usages.impl.rules.UsageTypeProvider;
import com.intellij.usages.rules.UsageFilteringRule;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetClass;
import org.jetbrains.jet.lang.psi.JetFunction;
+import org.jetbrains.jet.lang.psi.JetObjectDeclarationName;
+import org.jetbrains.jet.lang.psi.JetProperty;
import org.jetbrains.jet.plugin.JetLightProjectDescriptor;
import org.jetbrains.jet.plugin.PluginTestCaseBase;
import org.jetbrains.jet.plugin.findUsages.JetImportFilteringRule;
@@ -55,25 +61,119 @@ public class JetFindUsagesTest extends LightCodeInsightFixtureTestCase {
myFixture.setTestDataPath(PluginTestCaseBase.getTestDataPathBase() + "/findUsages");
}
- public void testFindClassUsages() {
+ public void testFindClassJavaUsages() {
doTestWithoutFiltering(
- Lists.newArrayList("findClassUsages/Server.kt", "findClassUsages/Client.java"),
+ Lists.newArrayList("findClassUsages/javaUsages/Server.kt", "findClassUsages/javaUsages/Client.java"),
JetClass.class,
- Lists.newArrayList("(4: 13) private Server myServer;"));
+ Lists.newArrayList("Field declaration (4: 13) private Server myServer;"));
+ }
+
+ public void testFindClassKotlinUsages1() {
+ doTestWithoutFiltering(
+ Lists.newArrayList("findClassUsages/kotlinUsages1/Server.kt", "findClassUsages/kotlinUsages1/Client.kt"),
+ JetClass.class,
+ Lists.newArrayList(
+ "Class/object property type (6: 21) var nextServer: Server? = null",
+ "Function return types (14: 26) fun getNextServer(): Server? {",
+ "Function return types (32: 21) fun Any.asServer(): Server? {",
+ "Import directive (3: 15) import server.Server",
+ "Local variable type (10: 21) val server: Server = s",
+ "Nested class/object (7: 16) val name = Server.NAME",
+ "Parameter type (24: 19) fun Client.bar(s: Server) {",
+ "Parameter type (9: 16) fun foo(s: Server) {",
+ "Super type qualifier (19: 15) super.work()",
+ "Supertype (5: 15) class Client: Server {",
+ "Target type of 'as' operation (33: 40) return if (this is Server) this as Server else null",
+ "Target type of 'is' operation (33: 24) return if (this is Server) this as Server else null"
+ ));
+ }
+
+ public void testFindClassKotlinUsages2() {
+ doTestWithoutFiltering(
+ Lists.newArrayList("findClassUsages/kotlinUsages2/Server.kt", "findClassUsages/kotlinUsages2/Client.kt"),
+ JetClass.class,
+ Lists.newArrayList(
+ "Annotation (5: 1) X(\"\")",
+ "Import directive (3: 15) import server.X"
+ ));
+ }
+
+ public void testFindClassKotlinUsages3() {
+ doTestWithoutFiltering(
+ Lists.newArrayList("findClassUsages/kotlinUsages3/Server.kt", "findClassUsages/kotlinUsages3/Client.kt"),
+ JetClass.class,
+ Lists.newArrayList(
+ "Import directive (3: 15) import server.Data",
+ "Type argument (9: 16) val c = Client()",
+ "Type constraint (5: 17) class Client where X: Data {",
+ "Type constraint (5: 35) class Client where X: Data {"
+ ));
}
public void testFindUsagesUnresolvedAnnotation() {
doTestWithoutFiltering(
Lists.newArrayList("unresolvedAnnotation/Server.kt", "unresolvedAnnotation/Client.java"),
JetClass.class,
- Lists.newArrayList("(1: 29) public class Client extends Foo {}"));
+ Lists.newArrayList("Usage in extends/implements clause (1: 29) public class Client extends Foo {}"));
}
- public void testFindMethodUsages() {
+ public void testFindMethodJavaUsages() {
doTestWithoutFiltering(
- Lists.newArrayList("findMethodUsages/Server.kt", "findMethodUsages/Client.java"),
+ Lists.newArrayList("findMethodUsages/javaUsages/Server.kt", "findMethodUsages/javaUsages/Client.java"),
JetFunction.class,
- Lists.newArrayList("(6: 16) server.processRequest();"));
+ Lists.newArrayList("Unclassified usage (6: 16) server.processRequest();"));
+ }
+
+ public void testFindMethodKotlinUsages() {
+ doTestWithoutFiltering(
+ Lists.newArrayList("findMethodUsages/kotlinUsages/Server.kt", "findMethodUsages/kotlinUsages/Client.kt"),
+ JetFunction.class,
+ Lists.newArrayList(
+ "Callable reference (6: 23) val methodRef = ::processRequest()",
+ "Function call (10: 9) processRequest()",
+ "Import directive (3: 15) import server.processRequest"
+ ));
+ }
+
+ public void testFindPropertyJavaUsages() {
+ doTestWithoutFiltering(
+ Lists.newArrayList("findPropertyUsages/javaUsages/Server.kt", "findPropertyUsages/javaUsages/Client.java"),
+ JetProperty.class,
+ Lists.newArrayList(
+ "Unclassified usage (7: 40) println(\"foo = \" + O.instance$.getFoo())"
+ ));
+ }
+
+ public void testFindPropertyKotlinUsages() {
+ doTestWithoutFiltering(
+ Lists.newArrayList("findPropertyUsages/kotlinUsages/Server.kt", "findPropertyUsages/kotlinUsages/Client.kt"),
+ JetProperty.class,
+ Lists.newArrayList(
+ "Import directive (3: 15) import server.foo",
+ "Receiver (8: 35) println(\"length: ${server.foo.length()}\")",
+ "Selector (7: 33) println(\"foo = ${server.foo}\")"
+ ));
+ }
+
+ public void testFindObjectJavaUsages() {
+ doTestWithoutFiltering(
+ Lists.newArrayList("findObjectUsages/javaUsages/Server.kt", "findObjectUsages/javaUsages/Client.java"),
+ JetObjectDeclarationName.class,
+ Lists.newArrayList(
+ "Class static member access (7: 28) println(\"foo = \" + O.instance$.getFoo())",
+ "Usage in import (3: 15) import server.O"
+ ));
+ }
+
+ public void testFindObjectKotlinUsages() {
+ doTestWithoutFiltering(
+ Lists.newArrayList("findObjectUsages/kotlinUsages/Server.kt", "findObjectUsages/kotlinUsages/Client.kt"),
+ JetObjectDeclarationName.class,
+ Lists.newArrayList(
+ "Import directive (3: 15) import server.O",
+ "Receiver (7: 26) println(\"foo = ${O.foo}\")",
+ "Value read (8: 19) val obj = O"
+ ));
}
public void testFindWithFilteringImports() {
@@ -81,18 +181,22 @@ public class JetFindUsagesTest extends LightCodeInsightFixtureTestCase {
JetClass.class,
2,
Lists.newArrayList(new JetImportFilteringRule()),
- Lists.newArrayList("(5: 9) val a = Test()"));
+ Lists.newArrayList("Instantiation (5: 9) val a = Test()"));
}
- private void doTestWithoutFiltering(Collection files, Class caretElementClass, Collection expectedUsages) {
+ private void doTestWithoutFiltering(
+ Collection files,
+ Class caretElementClass,
+ Collection expectedUsages
+ ) {
doTest(files, caretElementClass, expectedUsages.size(), Collections.emptyList(), expectedUsages);
}
- private void doTest(
+ private void doTest(
Collection files,
Class caretElementClass,
int numberOfNotFilteredUsages,
- final Collection extends UsageFilteringRule> filters,
+ Collection extends UsageFilteringRule> filters,
Collection expectedUsages
) {
myFixture.configureByFiles(ArrayUtil.toObjectArray(files, String.class));
@@ -103,34 +207,60 @@ public class JetFindUsagesTest extends LightCodeInsightFixtureTestCase {
assertEquals(numberOfNotFilteredUsages, usageInfos.size());
- Collection filteredUsages =
- Collections2.filter(
- Collections2.transform(usageInfos, new Function() {
- @Override
- public UsageInfo2UsageAdapter apply(@Nullable UsageInfo usageInfo) {
- assert (usageInfo != null);
-
- UsageInfo2UsageAdapter usageAdapter = new UsageInfo2UsageAdapter(usageInfo);
- for (UsageFilteringRule filter : filters) {
- if (!filter.isVisible(usageAdapter)) {
- return null;
- }
- }
-
- return usageAdapter;
- }
- }),
- Predicates.notNull());
+ Collection filteredUsages = getUsageAdapters(filters, usageInfos);
Function convertToString = new Function() {
@Override
public String apply(@Nullable UsageInfo2UsageAdapter usageAdapter) {
assert usageAdapter != null;
- return Joiner.on("").join(Arrays.asList(usageAdapter.getPresentation().getText()));
+ return getUsageType(usageAdapter.getElement())
+ + " " + Joiner.on("").join(Arrays.asList(usageAdapter.getPresentation().getText()));
}
};
Collection finalUsages = Ordering.natural().sortedCopy(Collections2.transform(filteredUsages, convertToString));
assertOrderedEquals(finalUsages, Ordering.natural().sortedCopy(expectedUsages));
}
+
+ private static Collection getUsageAdapters(
+ final Collection extends UsageFilteringRule> filters,
+ Collection usageInfos
+ ) {
+ return Collections2.filter(
+ Collections2.transform(usageInfos, new Function() {
+ @Override
+ public UsageInfo2UsageAdapter apply(@Nullable UsageInfo usageInfo) {
+ assert (usageInfo != null);
+
+ UsageInfo2UsageAdapter usageAdapter = new UsageInfo2UsageAdapter(usageInfo);
+ for (UsageFilteringRule filter : filters) {
+ if (!filter.isVisible(usageAdapter)) {
+ return null;
+ }
+ }
+
+ return usageAdapter;
+ }
+ }),
+ Predicates.notNull());
+ }
+
+ @Nullable
+ private static UsageType getUsageType(PsiElement element) {
+ if (element == null) return null;
+
+ if (PsiTreeUtil.getParentOfType(element, PsiComment.class, false) != null) {
+ return UsageType.COMMENT_USAGE;
+ }
+
+ UsageTypeProvider[] providers = Extensions.getExtensions(UsageTypeProvider.EP_NAME);
+ for (UsageTypeProvider provider : providers) {
+ UsageType usageType = provider.getUsageType(element);
+ if (usageType != null) {
+ return usageType;
+ }
+ }
+
+ return UsageType.UNCLASSIFIED;
+ }
}