diff --git a/annotations/com/google/common/collect/annotations.xml b/annotations/com/google/common/collect/annotations.xml index f10679364a2..83405f3d0ea 100644 --- a/annotations/com/google/common/collect/annotations.xml +++ b/annotations/com/google/common/collect/annotations.xml @@ -1,4 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/annotations/com/intellij/lang/cacheBuilder/annotations.xml b/annotations/com/intellij/lang/cacheBuilder/annotations.xml new file mode 100644 index 00000000000..a7b9d99c9ca --- /dev/null +++ b/annotations/com/intellij/lang/cacheBuilder/annotations.xml @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/annotations/com/intellij/openapi/roots/annotations.xml b/annotations/com/intellij/openapi/roots/annotations.xml new file mode 100644 index 00000000000..d3fe22643d8 --- /dev/null +++ b/annotations/com/intellij/openapi/roots/annotations.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/annotations/com/intellij/util/indexing/annotations.xml b/annotations/com/intellij/util/indexing/annotations.xml new file mode 100644 index 00000000000..68d2f5893af --- /dev/null +++ b/annotations/com/intellij/util/indexing/annotations.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetMultiDeclaration.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetMultiDeclaration.java index 698b558d871..9d0d56f9b31 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetMultiDeclaration.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetMultiDeclaration.java @@ -17,11 +17,13 @@ package org.jetbrains.jet.lang.psi; import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiElement; import com.intellij.psi.tree.TokenSet; import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.JetNodeTypes; +import org.jetbrains.jet.lexer.JetTokens; import java.util.List; @@ -55,4 +57,14 @@ public class JetMultiDeclaration extends JetDeclarationImpl { public ASTNode getValOrVarNode() { return getNode().findChildByType(TokenSet.create(VAL_KEYWORD, VAR_KEYWORD)); } + + @Nullable + public PsiElement getRPar() { + return findChildByType(JetTokens.RPAR); + } + + @Nullable + public PsiElement getLPar() { + return findChildByType(JetTokens.LPAR); + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java index 08cbb0f4c73..740970b533f 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java @@ -898,7 +898,8 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { else if (OperatorConventions.EQUALS_OPERATIONS.contains(operationType)) { result = visitEquality(expression, context, operationSign, left, right); } - else if (operationType == JetTokens.EQEQEQ || operationType == JetTokens.EXCLEQEQEQ) { + else if (OperatorConventions.IDENTITY_EQUALS_OPERATIONS.contains(operationType)) { + context.trace.record(REFERENCE_TARGET, operationSign, KotlinBuiltIns.getInstance().getIdentityEquals()); ensureNonemptyIntersectionOfOperandTypes(expression, context); // TODO : Check comparison pointlessness result = JetTypeInfo.create(KotlinBuiltIns.getInstance().getBooleanType(), context.dataFlowInfo); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/OperatorConventions.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/OperatorConventions.java index 88b61d1cf18..0392ee47cc8 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/OperatorConventions.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/OperatorConventions.java @@ -17,7 +17,6 @@ package org.jetbrains.jet.lang.types.expressions; import com.google.common.collect.ImmutableBiMap; -import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -28,6 +27,7 @@ import org.jetbrains.jet.lexer.JetTokens; public class OperatorConventions { public static final Name EQUALS = Name.identifier("equals"); + public static final Name IDENTITY_EQUALS = Name.identifier("identityEquals"); public static final Name COMPARE_TO = Name.identifier("compareTo"); public static final Name CONTAINS = Name.identifier("contains"); @@ -77,6 +77,9 @@ public class OperatorConventions { public static final ImmutableSet EQUALS_OPERATIONS = ImmutableSet.of(JetTokens.EQEQ, JetTokens.EXCLEQ); + public static final ImmutableSet IDENTITY_EQUALS_OPERATIONS = + ImmutableSet.of(JetTokens.EQEQEQ, JetTokens.EXCLEQEQEQ); + public static final ImmutableSet IN_OPERATIONS = ImmutableSet.of(JetTokens.IN_KEYWORD, JetTokens.NOT_IN); @@ -88,7 +91,7 @@ public class OperatorConventions { .put(JetTokens.MINUSEQ, Name.identifier("minusAssign")) .build(); - public static final ImmutableMap ASSIGNMENT_OPERATION_COUNTERPARTS = ImmutableMap.builder() + public static final ImmutableBiMap ASSIGNMENT_OPERATION_COUNTERPARTS = ImmutableBiMap.builder() .put(JetTokens.MULTEQ, JetTokens.MUL) .put(JetTokens.DIVEQ, JetTokens.DIV) .put(JetTokens.PERCEQ, JetTokens.PERC) @@ -100,7 +103,7 @@ public class OperatorConventions { .put(JetTokens.ANDAND, Name.identifier("and")) .put(JetTokens.OROR, Name.identifier("or")) .build(); - + @Nullable public static Name getNameForOperationSymbol(@NotNull JetToken token) { Name name = UNARY_OPERATION_NAMES.get(token); diff --git a/compiler/frontend/src/org/jetbrains/jet/lexer/JetTokens.java b/compiler/frontend/src/org/jetbrains/jet/lexer/JetTokens.java index 371a2e7b1ac..a960ca01afa 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lexer/JetTokens.java +++ b/compiler/frontend/src/org/jetbrains/jet/lexer/JetTokens.java @@ -105,7 +105,7 @@ public interface JetTokens { JetSingleValueToken EQEQEQ = new JetSingleValueToken("EQEQEQ", "==="); JetSingleValueToken ARROW = new JetSingleValueToken("ARROW", "->"); JetSingleValueToken DOUBLE_ARROW = new JetSingleValueToken("DOUBLE_ARROW", "=>"); - JetSingleValueToken EXCLEQEQEQ = new JetSingleValueToken("EXCLEQEQEQ", "!==="); + JetSingleValueToken EXCLEQEQEQ = new JetSingleValueToken("EXCLEQEQEQ", "!=="); JetSingleValueToken EQEQ = new JetSingleValueToken("EQEQ", "=="); JetSingleValueToken EXCLEQ = new JetSingleValueToken("EXCLEQ", "!="); JetSingleValueToken EXCLEXCL = new JetSingleValueToken("EXCLEXCL", "!!"); diff --git a/core/descriptors/src/org/jetbrains/jet/lang/types/lang/KotlinBuiltIns.java b/core/descriptors/src/org/jetbrains/jet/lang/types/lang/KotlinBuiltIns.java index 7ebbefb5f86..c5589605509 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/types/lang/KotlinBuiltIns.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/types/lang/KotlinBuiltIns.java @@ -18,6 +18,7 @@ package org.jetbrains.jet.lang.types.lang; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; +import kotlin.KotlinPackage; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.PlatformToKotlinClassMap; @@ -881,4 +882,15 @@ public class KotlinBuiltIns { public JetType getDefaultBound() { return getNullableAnyType(); } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + // GET FUNCTION + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + @NotNull + public FunctionDescriptor getIdentityEquals() { + return KotlinPackage.first(getBuiltInsPackageFragment().getMemberScope().getFunctions(Name.identifier("identityEquals"))); + } } diff --git a/idea/src/org/jetbrains/jet/plugin/findUsages/JetFindUsagesProvider.kt b/idea/src/org/jetbrains/jet/plugin/findUsages/JetFindUsagesProvider.kt index 08e7e018d5b..11a9fb6e92c 100644 --- a/idea/src/org/jetbrains/jet/plugin/findUsages/JetFindUsagesProvider.kt +++ b/idea/src/org/jetbrains/jet/plugin/findUsages/JetFindUsagesProvider.kt @@ -21,20 +21,13 @@ import com.intellij.lang.findUsages.FindUsagesProvider import com.intellij.psi.PsiElement import com.intellij.psi.PsiNamedElement import org.jetbrains.jet.lang.psi.* -import org.jetbrains.jet.lexer.JetLexer -import com.intellij.lang.cacheBuilder.DefaultWordsScanner -import org.jetbrains.jet.lexer.JetTokens -import com.intellij.psi.tree.TokenSet -import org.jetbrains.jet.plugin.refactoring.changeSignature.JetParameterInfo public class JetFindUsagesProvider : FindUsagesProvider { - class JetWordsScanner : DefaultWordsScanner(JetLexer(), TokenSet.create(JetTokens.IDENTIFIER), JetTokens.COMMENTS, JetTokens.STRINGS) - public override fun canFindUsagesFor(psiElement: PsiElement): Boolean = psiElement is JetNamedDeclaration public override fun getWordsScanner(): WordsScanner = - JetWordsScanner() + KotlinWordsScanner() public override fun getHelpId(psiElement: PsiElement): String? = null diff --git a/idea/src/org/jetbrains/jet/plugin/findUsages/KotlinWordsScanner.kt b/idea/src/org/jetbrains/jet/plugin/findUsages/KotlinWordsScanner.kt new file mode 100644 index 00000000000..28ab0dd4673 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/findUsages/KotlinWordsScanner.kt @@ -0,0 +1,58 @@ +/* + * Copyright 2010-2014 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 org.jetbrains.jet.plugin.search.usagesSearch.* +import com.intellij.lang.cacheBuilder.WordsScanner +import com.intellij.util.Processor +import org.jetbrains.jet.lexer.JetLexer +import com.intellij.lang.cacheBuilder.WordOccurrence +import org.jetbrains.jet.lexer.JetTokens +import com.intellij.lang.cacheBuilder.SimpleWordsScanner +import org.jetbrains.jet.lang.types.expressions.OperatorConventions + +class KotlinWordsScanner() : WordsScanner { + private val lexer = JetLexer() + private val simpleWordsScanner = SimpleWordsScanner() + + fun scanWords(kind: WordOccurrence.Kind, processor: Processor) { + val tokenStart = lexer.getTokenStart() + simpleWordsScanner.processWords(lexer.getTokenSequence()) { + it!!.init(lexer.getBufferSequence(), tokenStart + it.getStart(), tokenStart + it.getEnd(), kind) + processor.process(it) + } + } + + override fun processWords(fileText: CharSequence, processor: Processor) { + lexer.start(fileText) + + val occurrence = WordOccurrence(null, 0, 0, null) + + stream { lexer.getTokenType() }.forEach { elementType -> + // todo: replace with when + if (ALL_SEARCHABLE_OPERATIONS.contains(elementType)) { + occurrence.init(lexer.getBufferSequence(), lexer.getTokenStart(), lexer.getTokenEnd(), WordOccurrence.Kind.CODE) + processor.process(occurrence) + } + else if (JetTokens.COMMENTS.contains(elementType)) scanWords(WordOccurrence.Kind.COMMENTS, processor) + else if (JetTokens.STRINGS.contains(elementType)) scanWords(WordOccurrence.Kind.LITERALS, processor) + else scanWords(WordOccurrence.Kind.CODE, processor) + + lexer.advance() + } + } +} diff --git a/idea/src/org/jetbrains/jet/plugin/references/JetMultiDeclarationReference.kt b/idea/src/org/jetbrains/jet/plugin/references/JetMultiDeclarationReference.kt index c9827ea50af..842bab40828 100644 --- a/idea/src/org/jetbrains/jet/plugin/references/JetMultiDeclarationReference.kt +++ b/idea/src/org/jetbrains/jet/plugin/references/JetMultiDeclarationReference.kt @@ -20,6 +20,10 @@ import org.jetbrains.jet.lang.psi.JetMultiDeclaration import org.jetbrains.jet.lang.resolve.BindingContext import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor import com.intellij.openapi.util.TextRange +import java.util.Collections +import org.jetbrains.jet.lang.descriptors.ClassDescriptor +import org.jetbrains.jet.lang.resolve.source.PsiSourceElement +import org.jetbrains.jet.lang.resolve.source.getPsi class JetMultiDeclarationReference(element: JetMultiDeclaration) : JetMultiReference(element) { override fun getTargetDescriptors(context: BindingContext): Collection { @@ -28,14 +32,10 @@ class JetMultiDeclarationReference(element: JetMultiDeclaration) : JetMultiRefer }.filterNotNull() } - override fun getRangeInElement(): TextRange? { - val entries = expression.getEntries() - if (entries.isEmpty()) { - return TextRange.EMPTY_RANGE - } - val start = entries.first!!.getStartOffsetInParent() - val end = entries.last!!.getStartOffsetInParent() + entries.last!!.getTextLength() - return TextRange(start, end) + val start = expression.getLPar() + val end = expression.getRPar() + if (start == null || end == null) return TextRange.EMPTY_RANGE + return TextRange(start.getStartOffsetInParent(), end.getStartOffsetInParent()) } } diff --git a/idea/src/org/jetbrains/jet/plugin/references/JetReference.kt b/idea/src/org/jetbrains/jet/plugin/references/JetReference.kt index 180a5479f83..4072f2fe7db 100644 --- a/idea/src/org/jetbrains/jet/plugin/references/JetReference.kt +++ b/idea/src/org/jetbrains/jet/plugin/references/JetReference.kt @@ -28,17 +28,13 @@ import org.jetbrains.jet.lang.resolve.BindingContext import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache import java.util.Collections import java.util.HashSet -import org.jetbrains.jet.lang.resolve.BindingContextUtils import org.jetbrains.jet.lang.descriptors.PackageViewDescriptor import com.intellij.psi.JavaPsiFacade import org.jetbrains.jet.lang.psi.JetReferenceExpression -import com.intellij.psi.search.GlobalSearchScope import org.jetbrains.jet.plugin.codeInsight.DescriptorToDeclarationUtil import com.intellij.util.containers.ContainerUtil -import org.jetbrains.jet.asJava.* import org.jetbrains.jet.lang.psi.JetElement import org.jetbrains.jet.utils.keysToMap -import com.intellij.psi.PsiMethod import org.jetbrains.jet.plugin.search.allScope import org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils @@ -65,20 +61,16 @@ abstract class AbstractJetReference(element: T) return null } + override fun isReferenceTo(element: PsiElement?): Boolean { + return element != null && matchesTarget(element) + } + override fun getCanonicalText(): String = "" override fun handleElementRename(newElementName: String?): PsiElement? = throw IncorrectOperationException() override fun bindToElement(element: PsiElement): PsiElement = throw IncorrectOperationException() - protected fun checkElementMatch(referenceTarget: PsiElement, elementToMatch: PsiElement): Boolean { - val unwrappedTarget = referenceTarget.namedUnwrappedElement - val unwrappedElementToMatch = elementToMatch.namedUnwrappedElement - - return (unwrappedTarget == unwrappedElementToMatch) || - (referenceTarget is PsiMethod && referenceTarget.isConstructor() && referenceTarget.getContainingClass() == elementToMatch) - } - [suppress("CAST_NEVER_SUCCEEDS")] override fun getVariants(): Array = PsiReference.EMPTY_ARRAY as Array @@ -152,21 +144,6 @@ public abstract class JetSimpleReference(expression: } return context[BindingContext.AMBIGUOUS_REFERENCE_TARGET, expression].orEmpty() } - - override fun isReferenceTo(element: PsiElement?): Boolean { - val resolvedElement = resolve() - if (resolvedElement == null || element == null) { - return false - } - return checkElementMatch(resolvedElement, element) - } } -public abstract class JetMultiReference(expression: T) : AbstractJetReference(expression) { - override fun isReferenceTo(element: PsiElement?): Boolean { - if (element == null) { - return false - } - return multiResolve(false).map { it.getElement() }.filterNotNull().any { checkElementMatch(it, element) } - } -} +public abstract class JetMultiReference(expression: T) : AbstractJetReference(expression) diff --git a/idea/src/org/jetbrains/jet/plugin/references/referenceUtil.kt b/idea/src/org/jetbrains/jet/plugin/references/referenceUtil.kt new file mode 100644 index 00000000000..cd9ac1bc044 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/references/referenceUtil.kt @@ -0,0 +1,61 @@ +/* + * Copyright 2010-2014 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.references + +import com.intellij.psi.PsiReference +import com.intellij.psi.PsiElement +import org.jetbrains.jet.asJava.unwrapped +import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache +import org.jetbrains.jet.lang.resolve.BindingContext +import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor +import com.intellij.psi.PsiMethod +import org.jetbrains.jet.lang.psi.JetPropertyAccessor +import org.jetbrains.jet.lang.psi.psiUtil.getParentByType +import org.jetbrains.jet.lang.psi.JetProperty +import java.util.HashSet +import com.intellij.util.containers.ContainerUtil +import org.jetbrains.jet.lang.psi.JetNamedDeclaration + +// Navigation element of the resolved reference +// For property accessor return enclosing property +val PsiReference.unwrappedTargets: Set + get() { + fun PsiElement.adjust(): PsiElement? { + val target = unwrapped + return if (target is JetPropertyAccessor) target.getParentByType(javaClass()) else target + } + + return when (this) { + is JetMultiReference<*> -> multiResolve(false).map { it.getElement()?.adjust() }.filterNotNullTo(HashSet()) + else -> ContainerUtil.createMaybeSingletonSet(resolve()?.adjust()) + } + } + +fun PsiReference.matchesTarget(target: PsiElement): Boolean { + val unwrapped = target.unwrapped + return when { + unwrapped in unwrappedTargets -> + true + + this is JetReference + && unwrappedTargets.any { it is PsiMethod && it.isConstructor() && it.getContainingClass() == unwrapped } -> + true + + else -> + false + } +} diff --git a/idea/src/org/jetbrains/jet/plugin/search/ideaExtensions/KotlinReferencesSearcher.java b/idea/src/org/jetbrains/jet/plugin/search/ideaExtensions/KotlinReferencesSearcher.java index 44d6a52467f..bde2108f295 100644 --- a/idea/src/org/jetbrains/jet/plugin/search/ideaExtensions/KotlinReferencesSearcher.java +++ b/idea/src/org/jetbrains/jet/plugin/search/ideaExtensions/KotlinReferencesSearcher.java @@ -24,11 +24,13 @@ import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.Processor; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.asJava.AsJavaPackage; import org.jetbrains.jet.asJava.LightClassUtil; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.java.jetAsJava.KotlinLightMethod; import org.jetbrains.jet.plugin.JetPluginUtil; +import org.jetbrains.jet.plugin.search.usagesSearch.*; public class KotlinReferencesSearcher extends QueryExecutorBase { public static void processJetClassOrObject( @@ -43,20 +45,48 @@ public class KotlinReferencesSearcher extends QueryExecutorBase consumer) { + public void processQuery( + @NotNull final ReferencesSearch.SearchParameters queryParameters, + @NotNull final Processor consumer + ) { PsiElement element = queryParameters.getElementToSearch(); - PsiElement unwrappedElement = AsJavaPackage.getUnwrapped(element); - if (unwrappedElement == null - || !JetPluginUtil.isInSource(unwrappedElement) - || JetPluginUtil.isKtFileInGradleProjectInWrongFolder(unwrappedElement)) return; + final PsiNamedElement unwrappedElement = AsJavaPackage.getNamedUnwrappedElement(element); + if (unwrappedElement == null || JetPluginUtil.isKtFileInGradleProjectInWrongFolder(unwrappedElement)) return; + ApplicationManager.getApplication().runReadAction( + new Runnable() { + @Override + public void run() { + KotlinPsiSearchHelper searchHelper = new KotlinPsiSearchHelper(queryParameters.getElementToSearch().getProject()); + UsagesSearchTarget searchTarget = new UsagesSearchTarget( + unwrappedElement, + queryParameters.getEffectiveSearchScope(), + UsagesSearchLocation.EVERYWHERE, + false + ); + UsagesSearchRequestItem requestItem = new UsagesSearchRequestItem( + searchTarget, + UsagesSearchPackage.getSpecialNamesToSearch(unwrappedElement), + UsagesSearchPackage.getIsTargetUsage() + ); + searchHelper.processFilesWithText(requestItem, consumer); + } + } + ); + + if (!JetPluginUtil.isInSource(unwrappedElement)) return; + + searchLightElements(queryParameters, element); + } + + private static void searchLightElements(ReferencesSearch.SearchParameters queryParameters, PsiElement element) { if (element instanceof JetClassOrObject) { processJetClassOrObject((JetClassOrObject) element, queryParameters); } @@ -99,7 +129,10 @@ public class KotlinReferencesSearcher extends QueryExecutorBase = ImmutableSet + .builder() + .addAll(UNARY_OPERATION_NAMES.keySet()) + .addAll(BINARY_OPERATION_NAMES.keySet()) + .addAll(ASSIGNMENT_OPERATIONS.keySet()) + .addAll(COMPARISON_OPERATIONS) + .addAll(EQUALS_OPERATIONS) + .addAll(IDENTITY_EQUALS_OPERATIONS) + .addAll(IN_OPERATIONS) + .add(JetTokens.LBRACKET) + .add(JetTokens.LPAR) + .add(JetTokens.BY_KEYWORD) + .build() + +public val ALL_SEARCHABLE_OPERATION_PATTERNS: Set = + ALL_SEARCHABLE_OPERATIONS.map { (it as JetSingleValueToken).getValue() }.toSet() + +public val INDEXING_OPERATION_NAMES: ImmutableSet = + ImmutableSet.of(Name.identifier("get"), Name.identifier("set")) + +public val INVOKE_OPERATION_NAME: Name = Name.identifier("invoke") + +public val ITERATOR_OPERATION_NAME: Name = Name.identifier("iterator") + +public val COMPONENT_OPERATION_PATTERN: Pattern = Pattern.compile("component\\d+") + +public val IN_OPERATIONS_TO_SEARCH: ImmutableSet = ImmutableSet.of(JetTokens.IN_KEYWORD) + +public val COMPARISON_OPERATIONS_TO_SEARCH: ImmutableSet = ImmutableSet.of(JetTokens.LT, JetTokens.GT) + +public fun Name.getOperationSymbolsToSearch(): Set { + when (this) { + COMPARE_TO -> return COMPARISON_OPERATIONS_TO_SEARCH + EQUALS -> return EQUALS_OPERATIONS + IDENTITY_EQUALS -> return IDENTITY_EQUALS_OPERATIONS + CONTAINS -> return IN_OPERATIONS_TO_SEARCH + INVOKE_OPERATION_NAME -> return ImmutableSet.of(JetTokens.LPAR) + ITERATOR_OPERATION_NAME -> return ImmutableSet.of(JetTokens.IN_KEYWORD) + in INDEXING_OPERATION_NAMES -> return ImmutableSet.of(JetTokens.LBRACKET) + } + + if (COMPONENT_OPERATION_PATTERN.matcher(asString()).matches()) return ImmutableSet.of(JetTokens.LPAR) + + val unaryOp = UNARY_OPERATION_NAMES.inverse()[this] + if (unaryOp != null) return ImmutableSet.of(unaryOp) + + val binaryOp = BINARY_OPERATION_NAMES.inverse()[this] + if (binaryOp != null) { + val assignmentOp = ASSIGNMENT_OPERATION_COUNTERPARTS.inverse()[binaryOp] + return if (assignmentOp != null) ImmutableSet.of(binaryOp, assignmentOp) else ImmutableSet.of(binaryOp) + } + + val assignmentOp = ASSIGNMENT_OPERATIONS.inverse()[this] + if (assignmentOp != null) return ImmutableSet.of(assignmentOp) + + return ImmutableSet.of() +} diff --git a/idea/src/org/jetbrains/jet/plugin/search/usagesSearch/searchHelpers.kt b/idea/src/org/jetbrains/jet/plugin/search/usagesSearch/searchHelpers.kt index e7bd532cd39..5b9c8217e66 100644 --- a/idea/src/org/jetbrains/jet/plugin/search/usagesSearch/searchHelpers.kt +++ b/idea/src/org/jetbrains/jet/plugin/search/usagesSearch/searchHelpers.kt @@ -18,8 +18,6 @@ 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 @@ -28,34 +26,35 @@ 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 import org.jetbrains.jet.lang.psi.JetParameter import org.jetbrains.jet.lang.psi.JetPsiUtil -import org.jetbrains.jet.lang.psi.psiUtil.* import org.jetbrains.jet.asJava.LightClassUtil.PropertyAccessorsPsiMethods import org.jetbrains.jet.lang.psi.psiUtil.* +import org.jetbrains.jet.lang.resolve.name.Name +import org.jetbrains.jet.lexer.JetSingleValueToken +import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache +import org.jetbrains.jet.lang.resolve.BindingContext +import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor +import org.jetbrains.jet.lexer.JetTokens +import org.jetbrains.jet.plugin.references.* +import org.jetbrains.jet.lang.psi.JetDeclaration +import com.intellij.util.containers.ContainerUtil -val isTargetUsage = (PsiReference::isTargetUsage).searchFilter - -fun JetNamedDeclaration.namesWithAccessors(readable: Boolean = true, writable: Boolean = true): List { - val name = getName()!! +val isTargetUsage = (PsiReference::matchesTarget).searchFilter +fun PsiNamedElement.getAccessorNames(readable: Boolean = true, writable: Boolean = true): List { fun PropertyAccessorsPsiMethods.toNameList(): List { val getter = getGetter() val setter = getSetter() - val result = arrayListOf(name) + val result = ArrayList() if (readable && getter != null) result.add(getter.getName()) if (writable && setter != null) result.add(setter.getName()) return result } - if (JetPsiUtil.isLocal(this)) return Collections.singletonList(name) + if (this !is JetDeclaration || JetPsiUtil.isLocal(this)) return Collections.emptyList() when (this) { is JetProperty -> @@ -66,21 +65,32 @@ fun JetNamedDeclaration.namesWithAccessors(readable: Boolean = true, writable: B } } - return Collections.singletonList(name) + return Collections.emptyList() +} + +public fun PsiNamedElement.getSpecialNamesToSearch(): List { + val name = getName() + return when { + name == null || !Name.isValidIdentifier(name) -> Collections.emptyList() + this is JetParameter -> { + if (!hasValOrVarNode()) return Collections.emptyList() + + val context = AnalyzerFacadeWithCache.getContextForElement(this) + val paramDescriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, this] as? ValueParameterDescriptor + context[BindingContext.DATA_CLASS_COMPONENT_FUNCTION, paramDescriptor]?.let { + listOf(it.getName().asString(), JetTokens.LPAR.getValue()) + } ?: Collections.emptyList() + } + else -> Name.identifier(name).getOperationSymbolsToSearch().map { (it as JetSingleValueToken).getValue() } + } } 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 is JetParameter -> (element as JetNamedDeclaration).namesWithAccessors() - else -> Collections.singletonList(name) - } + return with(target.element) { + ContainerUtil.createMaybeSingletonList(getName()) + getAccessorNames() + getSpecialNamesToSearch() } } @@ -185,7 +195,11 @@ class PropertyUsagesSearchHelper( skipImports: Boolean = false ) : DefaultSearchHelper(skipImports), OverrideSearchHelper { override fun makeWordList(target: UsagesSearchTarget): List { - return target.element.namesWithAccessors(readable = readUsages, writable = writeUsages) + return with(target.element) { + ContainerUtil.createMaybeSingletonList(getName()) + + getAccessorNames(readable = readUsages, writable = writeUsages) + + getSpecialNamesToSearch() + } } override fun makeFilter(target: UsagesSearchTarget): UsagesSearchFilter { diff --git a/idea/src/org/jetbrains/jet/plugin/search/usagesSearch/usagesSearch.kt b/idea/src/org/jetbrains/jet/plugin/search/usagesSearch/usagesSearch.kt index 12150a2bf07..1847cb671e3 100644 --- a/idea/src/org/jetbrains/jet/plugin/search/usagesSearch/usagesSearch.kt +++ b/idea/src/org/jetbrains/jet/plugin/search/usagesSearch/usagesSearch.kt @@ -19,7 +19,6 @@ package org.jetbrains.jet.plugin.search.usagesSearch import com.intellij.psi.PsiReference import com.intellij.util.QueryFactory import com.intellij.psi.search.SearchScope -import com.intellij.psi.PsiElement import com.intellij.psi.search.SearchRequestCollector import com.intellij.psi.search.SearchSession import com.intellij.psi.search.PsiSearchHelper @@ -29,7 +28,6 @@ import com.intellij.psi.search.SearchRequestQuery import com.intellij.util.UniqueResultsQuery import com.intellij.psi.search.searches.ReferenceDescriptor import com.intellij.util.containers.ContainerUtil -import com.intellij.openapi.application.ApplicationManager import com.intellij.psi.search.UsageSearchContext import com.intellij.psi.PsiElement import com.intellij.psi.search.RequestResultProcessor @@ -38,15 +36,22 @@ import com.intellij.openapi.application.QueryExecutorBase import com.intellij.psi.PsiReferenceService import com.intellij.openapi.progress.ProgressManager import com.intellij.psi.ReferenceRange -import java.util.Collections -import com.intellij.openapi.extensions.ExtensionPointName -import com.intellij.openapi.extensions.Extensions -import java.util.ArrayList -import com.intellij.util.EmptyQuery import com.intellij.openapi.project.Project -import java.util.ArrayDeque import org.jetbrains.jet.plugin.search.usagesSearch.UsagesSearchFilter.* import org.jetbrains.jet.plugin.search.and +import com.intellij.psi.impl.search.PsiSearchHelperImpl +import com.intellij.psi.search.GlobalSearchScope +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.psi.impl.cache.impl.id.IdIndexEntry +import java.util.Collections +import com.intellij.openapi.roots.FileIndexFacade +import com.intellij.util.indexing.FileBasedIndex +import com.intellij.psi.impl.cache.impl.id.IdIndex +import org.jetbrains.jet.plugin.refactoring.runReadAction +import com.intellij.psi.search.TextOccurenceProcessor +import org.jetbrains.jet.plugin.references.JetMultiDeclarationReference +import com.intellij.psi.PsiManager +import com.intellij.psi.impl.PsiManagerEx public data class UsagesSearchLocation( val inCode: Boolean = true, @@ -103,39 +108,61 @@ public data class UsagesSearchRequest(val project: Project, val items: List() { - { - class ResultProcessorImpl(private val node: UsagesSearchRequestItem) : RequestResultProcessor() { - private val referenceService = PsiReferenceService.getService()!! +public class KotlinPsiSearchHelper(private val project: Project): PsiSearchHelperImpl(PsiManager.getInstance(project) as PsiManagerEx) { + class ResultTextProcessorImpl( + private val node: UsagesSearchRequestItem, + private val consumer: Processor + ): TextOccurenceProcessor { + private val referenceService = PsiReferenceService.getService()!! - override fun processTextOccurrence(element: PsiElement, offsetInElement: Int, consumer: Processor): Boolean { - return referenceService.getReferences(element, PsiReferenceService.Hints.NO_HINTS).all { ref -> - ProgressManager.checkCanceled() + override fun execute(element: PsiElement, offsetInElement: Int): Boolean { + return referenceService.getReferences(element, PsiReferenceService.Hints.NO_HINTS).all { ref -> + ProgressManager.checkCanceled() - when { - !ReferenceRange.containsOffsetInElement(ref, offsetInElement) -> true - !node.filter.accepts(ref, node) -> true - else -> consumer.process(ref) - } + when { + !ReferenceRange.containsOffsetInElement(ref, offsetInElement) -> true + !node.filter.accepts(ref, node) -> true + else -> consumer.process(ref) } } } + } + override fun processFilesWithText( + scope: GlobalSearchScope, + searchContext: Short, + caseSensitively: Boolean, + text: String, + processor: Processor + ): Boolean { + if (text !in ALL_SEARCHABLE_OPERATION_PATTERNS) { + return super.processFilesWithText(scope, searchContext, caseSensitively, text, processor) + } + + val entries = Collections.singletonList(IdIndexEntry(text, caseSensitively)) + val index = FileIndexFacade.getInstance(project) + val checker: (Int?) -> Boolean = { (it!! and searchContext.toInt()) != 0 } + return runReadAction{ + FileBasedIndex.getInstance().processFilesContainingAllKeys(IdIndex.NAME, entries, scope, checker) { file -> + !index.shouldBeFound(scope, file) || processor.process(file) + } + }!! + } + + public fun processFilesWithText(item: UsagesSearchRequestItem, consumer: Processor): Boolean { + return item.words.all { word -> + val textProcessor = ResultTextProcessorImpl(item, consumer) + processElementsWithWord(textProcessor, item.target.scope, word, UsageSearchContext.IN_CODE, true) + } + } +} + +public object UsagesSearch: QueryFactory() { + { object ExecutorImpl: QueryExecutorBase() { override fun processQuery(request: UsagesSearchRequest, consumer: Processor) { - for (item in request.items) { - with (item) { - if (filter != False) { - ApplicationManager.getApplication()?.runReadAction { - for (word in words) { - request.collector.searchWord( - word, target.scope, target.location.searchContext, true, ResultProcessorImpl(item) - ) - } - } - } - } - } + val searchHelper = KotlinPsiSearchHelper(request.project) + request.items.filter { it.filter != False }.all { searchHelper.processFilesWithText(it, consumer) } } } diff --git a/idea/src/org/jetbrains/jet/plugin/search/usagesSearch/utils.kt b/idea/src/org/jetbrains/jet/plugin/search/usagesSearch/utils.kt index 40d915cba0a..891c9a74e94 100644 --- a/idea/src/org/jetbrains/jet/plugin/search/usagesSearch/utils.kt +++ b/idea/src/org/jetbrains/jet/plugin/search/usagesSearch/utils.kt @@ -23,7 +23,6 @@ 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.descriptors.FunctionDescriptor @@ -38,14 +37,13 @@ import org.jetbrains.jet.lang.resolve.java.jetAsJava.KotlinLightMethod import org.jetbrains.jet.asJava.unwrapped import org.jetbrains.jet.lang.resolve.OverrideResolver import org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils - -// Navigation element of the resolved reference -// For property accessor return enclosing property -val PsiReference.unwrappedTarget: PsiElement? - get() { - val target = resolve()?.unwrapped - return if (target is JetPropertyAccessor) target.getParentByType(javaClass()) else target - } +import com.intellij.util.containers.ContainerUtil +import org.jetbrains.jet.plugin.references.JetMultiReference +import java.util.HashSet +import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor +import org.jetbrains.jet.plugin.references.JetReference +import com.intellij.psi.PsiMethod +import org.jetbrains.jet.plugin.references.* val JetDeclaration.descriptor: DeclarationDescriptor? get() = AnalyzerFacadeWithCache.getContextForElement(this).get(BindingContext.DECLARATION_TO_DESCRIPTOR, this) @@ -53,21 +51,19 @@ val JetDeclaration.descriptor: DeclarationDescriptor? val JetParameter.propertyDescriptor: PropertyDescriptor? get() = AnalyzerFacadeWithCache.getContextForElement(this).get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, this) -fun PsiReference.isTargetUsage(target: PsiElement): Boolean { - return target.unwrapped == unwrappedTarget -} - fun PsiReference.checkUsageVsOriginalDescriptor( target: JetDeclaration, declarationToDescriptor: (JetDeclaration) -> DeclarationDescriptor? = {it.descriptor}, checker: (usageDescriptor: DeclarationDescriptor, targetDescriptor: DeclarationDescriptor) -> Boolean ): Boolean { - val refTarget = unwrappedTarget - if (refTarget !is JetDeclaration) return false - - val usageDescriptor = declarationToDescriptor(refTarget) - val targetDescriptor = declarationToDescriptor(target) - return usageDescriptor != null && targetDescriptor != null && checker(usageDescriptor, targetDescriptor) + return unwrappedTargets.any { + if (it is JetDeclaration) { + val usageDescriptor = declarationToDescriptor(it) + val targetDescriptor = declarationToDescriptor(target) + usageDescriptor != null && targetDescriptor != null && checker(usageDescriptor, targetDescriptor) + } + else false + } } fun PsiReference.isImportUsage(): Boolean = diff --git a/idea/testData/findUsages/kotlin/conventions/compareTo.0.kt b/idea/testData/findUsages/kotlin/conventions/compareTo.0.kt new file mode 100644 index 00000000000..335a45476b3 --- /dev/null +++ b/idea/testData/findUsages/kotlin/conventions/compareTo.0.kt @@ -0,0 +1,20 @@ +// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetNamedFunction +// OPTIONS: usages + +class A(val n: Int) { + fun compareTo(other: A): Int = compareTo(other.n) + fun compareTo(m: Int): Int = n.compareTo(m) +} + +fun test() { + A(0) compareTo A(1) + A(0) < A(1) + A(0) <= A(1) + A(0) > A(1) + A(0) >= A(1) + A(0) compareTo 1 + A(0) < 1 + A(0) <= 1 + A(0) > 1 + A(0) >= 1 +} \ No newline at end of file diff --git a/idea/testData/findUsages/kotlin/conventions/compareTo.results.txt b/idea/testData/findUsages/kotlin/conventions/compareTo.results.txt new file mode 100644 index 00000000000..ac010259dec --- /dev/null +++ b/idea/testData/findUsages/kotlin/conventions/compareTo.results.txt @@ -0,0 +1,5 @@ +Function call (10: 10) A(0) compareTo A(1) +Function call (11: 10) A(0) < A(1) +Function call (12: 10) A(0) <= A(1) +Function call (13: 10) A(0) > A(1) +Function call (14: 10) A(0) >= A(1) diff --git a/idea/testData/findUsages/kotlin/conventions/componentFunctions.0.kt b/idea/testData/findUsages/kotlin/conventions/componentFunctions.0.kt new file mode 100644 index 00000000000..b39b11f4ca2 --- /dev/null +++ b/idea/testData/findUsages/kotlin/conventions/componentFunctions.0.kt @@ -0,0 +1,11 @@ +// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetParameter +// OPTIONS: usages + +data class A(val n: Int, val s: String, val o: Any) + +fun test() { + val a = A(1, "2", Any()) + a.n + a.component1() + val (x, y, z) = a +} \ No newline at end of file diff --git a/idea/testData/findUsages/kotlin/conventions/componentFunctions.results.txt b/idea/testData/findUsages/kotlin/conventions/componentFunctions.results.txt new file mode 100644 index 00000000000..a488cb0de61 --- /dev/null +++ b/idea/testData/findUsages/kotlin/conventions/componentFunctions.results.txt @@ -0,0 +1,3 @@ +Function call (9: 7) a.component1() +Value read (10: 9) val (x, y, z) = a +Value read (8: 7) a.n \ No newline at end of file diff --git a/idea/testData/findUsages/kotlin/conventions/componentFunctionsByRef.0.kt b/idea/testData/findUsages/kotlin/conventions/componentFunctionsByRef.0.kt new file mode 100644 index 00000000000..3a2f66864ee --- /dev/null +++ b/idea/testData/findUsages/kotlin/conventions/componentFunctionsByRef.0.kt @@ -0,0 +1,12 @@ +// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetParameter +// OPTIONS: usages +// FIND_BY_REF + +data class A(val n: Int, val s: String, val o: Any) + +fun test() { + val a = A(1, "2", Any()) + a.n + a.component1() + val (x, y, z) = a +} \ No newline at end of file diff --git a/idea/testData/findUsages/kotlin/conventions/componentFunctionsByRef.results.txt b/idea/testData/findUsages/kotlin/conventions/componentFunctionsByRef.results.txt new file mode 100644 index 00000000000..0978371c897 --- /dev/null +++ b/idea/testData/findUsages/kotlin/conventions/componentFunctionsByRef.results.txt @@ -0,0 +1,3 @@ +Function call (10: 7) a.component1() +Value read (11: 9) val (x, y, z) = a +Value read (9: 7) a.n \ No newline at end of file diff --git a/idea/testData/findUsages/kotlin/conventions/contains.0.kt b/idea/testData/findUsages/kotlin/conventions/contains.0.kt new file mode 100644 index 00000000000..73daf42c0dd --- /dev/null +++ b/idea/testData/findUsages/kotlin/conventions/contains.0.kt @@ -0,0 +1,16 @@ +// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetNamedFunction +// OPTIONS: usages + +class A(val n: Int) { + fun contains(k: Int): Boolean = k <= n +} + +fun test() { + A(2) contains 1 + 1 in A(2) + 1 !in A(2) + when (1) { + in A(2) -> {} + !in A(2) -> {} + } +} \ No newline at end of file diff --git a/idea/testData/findUsages/kotlin/conventions/contains.results.txt b/idea/testData/findUsages/kotlin/conventions/contains.results.txt new file mode 100644 index 00000000000..db3fe43d2fe --- /dev/null +++ b/idea/testData/findUsages/kotlin/conventions/contains.results.txt @@ -0,0 +1,5 @@ +Function call (10: 7) 1 in A(2) +Function call (11: 7) 1 !in A(2) +Function call (13: 9) in A(2) -> {} +Function call (14: 9) !in A(2) -> {} +Function call (9: 10) A(2) contains 1 diff --git a/idea/testData/findUsages/kotlin/conventions/equals.0.kt b/idea/testData/findUsages/kotlin/conventions/equals.0.kt new file mode 100644 index 00000000000..057e6dee345 --- /dev/null +++ b/idea/testData/findUsages/kotlin/conventions/equals.0.kt @@ -0,0 +1,14 @@ +// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetNamedFunction +// OPTIONS: usages + +class A(val n: Int) { + override fun equals(other: Any?): Boolean = other is A && other.n == n +} + +fun test() { + A(0) == A(1) + A(0) != A(1) + A(0) equals A(1) + A(0) === A(1) + A(0) !== A(1) +} \ No newline at end of file diff --git a/idea/testData/findUsages/kotlin/conventions/equals.results.txt b/idea/testData/findUsages/kotlin/conventions/equals.results.txt new file mode 100644 index 00000000000..c971a72ed66 --- /dev/null +++ b/idea/testData/findUsages/kotlin/conventions/equals.results.txt @@ -0,0 +1,4 @@ +Function call (10: 10) A(0) != A(1) +Function call (11: 10) A(0) equals A(1) +Function call (5: 71) override fun equals(other: Any?): Boolean = other is A && other.n == n +Function call (9: 10) A(0) == A(1) diff --git a/idea/testData/findUsages/kotlin/conventions/forIteration.0.kt b/idea/testData/findUsages/kotlin/conventions/forIteration.0.kt new file mode 100644 index 00000000000..3ecd4b1377f --- /dev/null +++ b/idea/testData/findUsages/kotlin/conventions/forIteration.0.kt @@ -0,0 +1,17 @@ +// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetNamedFunction +// OPTIONS: usages + +class A { + public fun iterator(): Iterator = throw IllegalStateException("") +} + +class B { + public fun iterator(): Iterator = throw IllegalStateException("") +} + +fun test() { + for (a in A()) {} + for (b in B()) {} + for (a in A()) {} + for (b in B()) {} +} \ No newline at end of file diff --git a/idea/testData/findUsages/kotlin/conventions/forIteration.results.txt b/idea/testData/findUsages/kotlin/conventions/forIteration.results.txt new file mode 100644 index 00000000000..c4d3ec3a0c3 --- /dev/null +++ b/idea/testData/findUsages/kotlin/conventions/forIteration.results.txt @@ -0,0 +1,2 @@ +Implicit iteration (13: 12) for (a in A()) {} +Implicit iteration (15: 12) for (a in A()) {} diff --git a/idea/testData/findUsages/kotlin/conventions/get.0.kt b/idea/testData/findUsages/kotlin/conventions/get.0.kt new file mode 100644 index 00000000000..080bdbcd3af --- /dev/null +++ b/idea/testData/findUsages/kotlin/conventions/get.0.kt @@ -0,0 +1,11 @@ +// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetNamedFunction +// OPTIONS: usages + +class B(val n: Int) { + fun get(i: Int): B = B(i) +} + +fun test() { + B(1).get(2) + B(1)[2] +} \ No newline at end of file diff --git a/idea/testData/findUsages/kotlin/conventions/get.results.txt b/idea/testData/findUsages/kotlin/conventions/get.results.txt new file mode 100644 index 00000000000..8304ef1f3ec --- /dev/null +++ b/idea/testData/findUsages/kotlin/conventions/get.results.txt @@ -0,0 +1,2 @@ +Function call (9: 10) B(1).get(2) +Implicit 'get' (10: 5) B(1)[2] \ No newline at end of file diff --git a/idea/testData/findUsages/kotlin/conventions/identityEquals.0.kt b/idea/testData/findUsages/kotlin/conventions/identityEquals.0.kt new file mode 100644 index 00000000000..04e72fcacaa --- /dev/null +++ b/idea/testData/findUsages/kotlin/conventions/identityEquals.0.kt @@ -0,0 +1,16 @@ +// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetNamedFunction +// OPTIONS: usages +// FIND_BY_REF + +class A(val n: Int) { + override fun equals(other: Any?): Boolean = other is A && other.n == n +} + +fun test() { + A(0) == A(1) + A(0) != A(1) + A(0) equals A(1) + A(0) identityEquals A(1) + A(0) === A(1) + A(0) !== A(1) +} \ No newline at end of file diff --git a/idea/testData/findUsages/kotlin/conventions/identityEquals.results.txt b/idea/testData/findUsages/kotlin/conventions/identityEquals.results.txt new file mode 100644 index 00000000000..6b238f0110c --- /dev/null +++ b/idea/testData/findUsages/kotlin/conventions/identityEquals.results.txt @@ -0,0 +1,3 @@ +Function call (13: 10) A(0) identityEquals A(1) +Function call (14: 10) A(0) === A(1) +Function call (15: 10) A(0) !== A(1) \ No newline at end of file diff --git a/idea/testData/findUsages/kotlin/conventions/inc.0.kt b/idea/testData/findUsages/kotlin/conventions/inc.0.kt new file mode 100644 index 00000000000..e7764ce02f9 --- /dev/null +++ b/idea/testData/findUsages/kotlin/conventions/inc.0.kt @@ -0,0 +1,13 @@ +// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetNamedFunction +// OPTIONS: usages + +class A(val n: Int) { + fun inc(): A = A(n + 1) +} + +fun test() { + var a = A(1) + a.inc() + ++a + a++ +} \ No newline at end of file diff --git a/idea/testData/findUsages/kotlin/conventions/inc.results.txt b/idea/testData/findUsages/kotlin/conventions/inc.results.txt new file mode 100644 index 00000000000..34be7f422a0 --- /dev/null +++ b/idea/testData/findUsages/kotlin/conventions/inc.results.txt @@ -0,0 +1,3 @@ +Function call (10: 7) a.inc() +Function call (11: 5) ++a +Function call (12: 6) a++ diff --git a/idea/testData/findUsages/kotlin/conventions/invoke.0.kt b/idea/testData/findUsages/kotlin/conventions/invoke.0.kt new file mode 100644 index 00000000000..a30cddd2cae --- /dev/null +++ b/idea/testData/findUsages/kotlin/conventions/invoke.0.kt @@ -0,0 +1,11 @@ +// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetNamedFunction +// OPTIONS: usages + +class B(val n: Int) { + fun invoke(i: Int): B = B(i) +} + +fun test() { + B(1).invoke(2) + B(1)(2) +} \ No newline at end of file diff --git a/idea/testData/findUsages/kotlin/conventions/invoke.results.txt b/idea/testData/findUsages/kotlin/conventions/invoke.results.txt new file mode 100644 index 00000000000..199554ae546 --- /dev/null +++ b/idea/testData/findUsages/kotlin/conventions/invoke.results.txt @@ -0,0 +1,2 @@ +Function call (9: 10) B(1).invoke(2) +Implicit 'invoke' (10: 5) B(1)(2) diff --git a/idea/testData/findUsages/kotlin/conventions/plus.0.kt b/idea/testData/findUsages/kotlin/conventions/plus.0.kt new file mode 100644 index 00000000000..11a06095ee7 --- /dev/null +++ b/idea/testData/findUsages/kotlin/conventions/plus.0.kt @@ -0,0 +1,19 @@ +// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetNamedFunction +// OPTIONS: usages + +class A(val n: Int) { + fun plus(m: Int): A = A(n + m) + fun plus(a: A): A = this + a.n +} + +fun test() { + A(0) + A(1) + 2 + A(0) plus A(1) plus 2 + A(0).plus(A(1).plus(2)) + + var a = A(0) + a += 1 + a += A(1) + + +A(0) +} \ No newline at end of file diff --git a/idea/testData/findUsages/kotlin/conventions/plus.results.txt b/idea/testData/findUsages/kotlin/conventions/plus.results.txt new file mode 100644 index 00000000000..1edea255478 --- /dev/null +++ b/idea/testData/findUsages/kotlin/conventions/plus.results.txt @@ -0,0 +1,5 @@ +Function call (12: 20) A(0).plus(A(1).plus(2)) +Function call (10: 17) A(0) + A(1) + 2 +Function call (11: 20) A(0) plus A(1) plus 2 +Function call (15: 7) a += 1 +Function call (6: 30) fun plus(a: A): A = this + a.n diff --git a/idea/testData/findUsages/kotlin/conventions/plusAssign.0.kt b/idea/testData/findUsages/kotlin/conventions/plusAssign.0.kt new file mode 100644 index 00000000000..9a14e9fcc80 --- /dev/null +++ b/idea/testData/findUsages/kotlin/conventions/plusAssign.0.kt @@ -0,0 +1,19 @@ +// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetNamedFunction +// OPTIONS: usages + +class A(var n: Int) { + fun plusAssign(m: Int) { + n += m + } + + fun plusAssign(a: A) { + this += a.n + } +} + +fun test() { + val a = A(0) + a.plusAssign(1) + a += 1 + a += A(1) +} \ No newline at end of file diff --git a/idea/testData/findUsages/kotlin/conventions/plusAssign.results.txt b/idea/testData/findUsages/kotlin/conventions/plusAssign.results.txt new file mode 100644 index 00000000000..d348956f494 --- /dev/null +++ b/idea/testData/findUsages/kotlin/conventions/plusAssign.results.txt @@ -0,0 +1,3 @@ +Function call (16: 7) a.plusAssign(1) +Function call (10: 14) this += a.n +Function call (17: 7) a += 1 diff --git a/idea/testData/findUsages/kotlin/conventions/set.0.kt b/idea/testData/findUsages/kotlin/conventions/set.0.kt new file mode 100644 index 00000000000..44146e5d235 --- /dev/null +++ b/idea/testData/findUsages/kotlin/conventions/set.0.kt @@ -0,0 +1,13 @@ +// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetNamedFunction +// OPTIONS: usages + +class B(val n: Int) { + fun set(i: Int, a: B) {} +} + +fun test() { + var a = B(1) + a.set(2, B(2)) + a[2] = B(2) + a[2] +} \ No newline at end of file diff --git a/idea/testData/findUsages/kotlin/conventions/set.results.txt b/idea/testData/findUsages/kotlin/conventions/set.results.txt new file mode 100644 index 00000000000..8b4ed0b9e49 --- /dev/null +++ b/idea/testData/findUsages/kotlin/conventions/set.results.txt @@ -0,0 +1,2 @@ +Function call (10: 7) a.set(2, B(2)) +Implicit 'set' (11: 5) a[2] = B(2) diff --git a/idea/testData/findUsages/kotlin/conventions/unaryMinus.0.kt b/idea/testData/findUsages/kotlin/conventions/unaryMinus.0.kt new file mode 100644 index 00000000000..fd57b14f8c4 --- /dev/null +++ b/idea/testData/findUsages/kotlin/conventions/unaryMinus.0.kt @@ -0,0 +1,11 @@ +// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetNamedFunction +// OPTIONS: usages + +class A(val n: Int) { + fun minus(): A = this +} + +fun test() { + A(1).minus() + -A(1) +} \ No newline at end of file diff --git a/idea/testData/findUsages/kotlin/conventions/unaryMinus.results.txt b/idea/testData/findUsages/kotlin/conventions/unaryMinus.results.txt new file mode 100644 index 00000000000..25bd7f5f48b --- /dev/null +++ b/idea/testData/findUsages/kotlin/conventions/unaryMinus.results.txt @@ -0,0 +1,2 @@ +Function call (9: 10) A(1).minus() +Function call (10: 5) -A(1) diff --git a/idea/tests/org/jetbrains/jet/findUsages/JetFindUsagesTestGenerated.java b/idea/tests/org/jetbrains/jet/findUsages/JetFindUsagesTestGenerated.java index 575b522c734..5a07ab7d847 100644 --- a/idea/tests/org/jetbrains/jet/findUsages/JetFindUsagesTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/findUsages/JetFindUsagesTestGenerated.java @@ -33,12 +33,90 @@ import org.jetbrains.jet.findUsages.AbstractJetFindUsagesTest; @InnerTestClasses({JetFindUsagesTestGenerated.Kotlin.class, JetFindUsagesTestGenerated.Java.class}) public class JetFindUsagesTestGenerated extends AbstractJetFindUsagesTest { @TestMetadata("idea/testData/findUsages/kotlin") - @InnerTestClasses({Kotlin.FindClassUsages.class, Kotlin.FindFunctionUsages.class, Kotlin.FindObjectUsages.class, Kotlin.FindPackageUsages.class, Kotlin.FindParameterUsages.class, Kotlin.FindPropertyUsages.class, Kotlin.FindTypeParameterUsages.class, Kotlin.FindWithFilteringImports.class, Kotlin.FindWithStructuralGrouping.class, Kotlin.UnresolvedAnnotation.class}) + @InnerTestClasses({Kotlin.Conventions.class, Kotlin.FindClassUsages.class, Kotlin.FindFunctionUsages.class, Kotlin.FindObjectUsages.class, Kotlin.FindPackageUsages.class, Kotlin.FindParameterUsages.class, Kotlin.FindPropertyUsages.class, Kotlin.FindTypeParameterUsages.class, Kotlin.FindWithFilteringImports.class, Kotlin.FindWithStructuralGrouping.class, Kotlin.UnresolvedAnnotation.class}) public static class Kotlin extends AbstractJetFindUsagesTest { public void testAllFilesPresentInKotlin() throws Exception { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/findUsages/kotlin"), Pattern.compile("^(.+)\\.0\\.kt$"), true); } + @TestMetadata("idea/testData/findUsages/kotlin/conventions") + public static class Conventions extends AbstractJetFindUsagesTest { + public void testAllFilesPresentInConventions() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/findUsages/kotlin/conventions"), Pattern.compile("^(.+)\\.0\\.kt$"), true); + } + + @TestMetadata("compareTo.0.kt") + public void testCompareTo() throws Exception { + doTest("idea/testData/findUsages/kotlin/conventions/compareTo.0.kt"); + } + + @TestMetadata("componentFunctions.0.kt") + public void testComponentFunctions() throws Exception { + doTest("idea/testData/findUsages/kotlin/conventions/componentFunctions.0.kt"); + } + + @TestMetadata("componentFunctionsByRef.0.kt") + public void testComponentFunctionsByRef() throws Exception { + doTest("idea/testData/findUsages/kotlin/conventions/componentFunctionsByRef.0.kt"); + } + + @TestMetadata("contains.0.kt") + public void testContains() throws Exception { + doTest("idea/testData/findUsages/kotlin/conventions/contains.0.kt"); + } + + @TestMetadata("equals.0.kt") + public void testEquals() throws Exception { + doTest("idea/testData/findUsages/kotlin/conventions/equals.0.kt"); + } + + @TestMetadata("forIteration.0.kt") + public void testForIteration() throws Exception { + doTest("idea/testData/findUsages/kotlin/conventions/forIteration.0.kt"); + } + + @TestMetadata("get.0.kt") + public void testGet() throws Exception { + doTest("idea/testData/findUsages/kotlin/conventions/get.0.kt"); + } + + @TestMetadata("identityEquals.0.kt") + public void testIdentityEquals() throws Exception { + doTest("idea/testData/findUsages/kotlin/conventions/identityEquals.0.kt"); + } + + @TestMetadata("inc.0.kt") + public void testInc() throws Exception { + doTest("idea/testData/findUsages/kotlin/conventions/inc.0.kt"); + } + + @TestMetadata("invoke.0.kt") + public void testInvoke() throws Exception { + doTest("idea/testData/findUsages/kotlin/conventions/invoke.0.kt"); + } + + @TestMetadata("plus.0.kt") + public void testPlus() throws Exception { + doTest("idea/testData/findUsages/kotlin/conventions/plus.0.kt"); + } + + @TestMetadata("plusAssign.0.kt") + public void testPlusAssign() throws Exception { + doTest("idea/testData/findUsages/kotlin/conventions/plusAssign.0.kt"); + } + + @TestMetadata("set.0.kt") + public void testSet() throws Exception { + doTest("idea/testData/findUsages/kotlin/conventions/set.0.kt"); + } + + @TestMetadata("unaryMinus.0.kt") + public void testUnaryMinus() throws Exception { + doTest("idea/testData/findUsages/kotlin/conventions/unaryMinus.0.kt"); + } + + } + @TestMetadata("idea/testData/findUsages/kotlin/findClassUsages") public static class FindClassUsages extends AbstractJetFindUsagesTest { public void testAllFilesPresentInFindClassUsages() throws Exception { @@ -597,6 +675,7 @@ public class JetFindUsagesTestGenerated extends AbstractJetFindUsagesTest { public static Test innerSuite() { TestSuite suite = new TestSuite("Kotlin"); suite.addTestSuite(Kotlin.class); + suite.addTestSuite(Conventions.class); suite.addTestSuite(FindClassUsages.class); suite.addTestSuite(FindFunctionUsages.class); suite.addTestSuite(FindObjectUsages.class);