Find Usages: Add support of naming conventions

#KT-1356 Fixed
This commit is contained in:
Alexey Sedunov
2014-07-16 18:06:38 +04:00
parent 8bd0dda459
commit d226a11c8e
48 changed files with 775 additions and 133 deletions
@@ -1,4 +1,29 @@
<root> <root>
<item name='com.google.common.collect.ImmutableBiMap com.google.common.collect.ImmutableBiMap&lt;V,K&gt; inverse()'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='com.google.common.collect.ImmutableSet com.google.common.collect.ImmutableSet&lt;E&gt; of()'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='com.google.common.collect.ImmutableSet com.google.common.collect.ImmutableSet&lt;E&gt; of(E)'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='com.google.common.collect.ImmutableSet com.google.common.collect.ImmutableSet&lt;E&gt; of(E, E)'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='com.google.common.collect.ImmutableSet com.google.common.collect.ImmutableSet.Builder&lt;E&gt; builder()'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='com.google.common.collect.ImmutableSet.Builder com.google.common.collect.ImmutableSet&lt;E&gt; build()'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='com.google.common.collect.ImmutableSet.Builder com.google.common.collect.ImmutableSet.Builder&lt;E&gt; add(E)'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item
name='com.google.common.collect.ImmutableSet.Builder com.google.common.collect.ImmutableSet.Builder&lt;E&gt; addAll(java.lang.Iterable&lt;? extends E&gt;)'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='com.google.common.collect.Lists java.util.ArrayList&lt;E&gt; newArrayList(E...)'> <item name='com.google.common.collect.Lists java.util.ArrayList&lt;E&gt; newArrayList(E...)'>
<annotation name='org.jetbrains.annotations.NotNull'/> <annotation name='org.jetbrains.annotations.NotNull'/>
</item> </item>
@@ -0,0 +1,10 @@
<root>
<item
name='com.intellij.lang.cacheBuilder.WordsScanner void processWords(java.lang.CharSequence, com.intellij.util.Processor&lt;com.intellij.lang.cacheBuilder.WordOccurrence&gt;) 0'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item
name='com.intellij.lang.cacheBuilder.WordsScanner void processWords(java.lang.CharSequence, com.intellij.util.Processor&lt;com.intellij.lang.cacheBuilder.WordOccurrence&gt;) 1'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
</root>
@@ -0,0 +1,6 @@
<root>
<item
name='com.intellij.openapi.roots.FileIndexFacade com.intellij.openapi.roots.FileIndexFacade getInstance(com.intellij.openapi.project.Project)'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
</root>
@@ -0,0 +1,5 @@
<root>
<item name='com.intellij.util.indexing.FileBasedIndex com.intellij.util.indexing.FileBasedIndex getInstance()'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
</root>
@@ -17,11 +17,13 @@
package org.jetbrains.jet.lang.psi; package org.jetbrains.jet.lang.psi;
import com.intellij.lang.ASTNode; import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.psi.tree.TokenSet; import com.intellij.psi.tree.TokenSet;
import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.JetNodeTypes; import org.jetbrains.jet.JetNodeTypes;
import org.jetbrains.jet.lexer.JetTokens;
import java.util.List; import java.util.List;
@@ -55,4 +57,14 @@ public class JetMultiDeclaration extends JetDeclarationImpl {
public ASTNode getValOrVarNode() { public ASTNode getValOrVarNode() {
return getNode().findChildByType(TokenSet.create(VAL_KEYWORD, VAR_KEYWORD)); 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);
}
} }
@@ -898,7 +898,8 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
else if (OperatorConventions.EQUALS_OPERATIONS.contains(operationType)) { else if (OperatorConventions.EQUALS_OPERATIONS.contains(operationType)) {
result = visitEquality(expression, context, operationSign, left, right); 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); ensureNonemptyIntersectionOfOperandTypes(expression, context);
// TODO : Check comparison pointlessness // TODO : Check comparison pointlessness
result = JetTypeInfo.create(KotlinBuiltIns.getInstance().getBooleanType(), context.dataFlowInfo); result = JetTypeInfo.create(KotlinBuiltIns.getInstance().getBooleanType(), context.dataFlowInfo);
@@ -17,7 +17,6 @@
package org.jetbrains.jet.lang.types.expressions; package org.jetbrains.jet.lang.types.expressions;
import com.google.common.collect.ImmutableBiMap; import com.google.common.collect.ImmutableBiMap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -28,6 +27,7 @@ import org.jetbrains.jet.lexer.JetTokens;
public class OperatorConventions { public class OperatorConventions {
public static final Name EQUALS = Name.identifier("equals"); 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 COMPARE_TO = Name.identifier("compareTo");
public static final Name CONTAINS = Name.identifier("contains"); public static final Name CONTAINS = Name.identifier("contains");
@@ -77,6 +77,9 @@ public class OperatorConventions {
public static final ImmutableSet<JetToken> EQUALS_OPERATIONS = public static final ImmutableSet<JetToken> EQUALS_OPERATIONS =
ImmutableSet.<JetToken>of(JetTokens.EQEQ, JetTokens.EXCLEQ); ImmutableSet.<JetToken>of(JetTokens.EQEQ, JetTokens.EXCLEQ);
public static final ImmutableSet<JetToken> IDENTITY_EQUALS_OPERATIONS =
ImmutableSet.<JetToken>of(JetTokens.EQEQEQ, JetTokens.EXCLEQEQEQ);
public static final ImmutableSet<JetToken> IN_OPERATIONS = public static final ImmutableSet<JetToken> IN_OPERATIONS =
ImmutableSet.<JetToken>of(JetTokens.IN_KEYWORD, JetTokens.NOT_IN); ImmutableSet.<JetToken>of(JetTokens.IN_KEYWORD, JetTokens.NOT_IN);
@@ -88,7 +91,7 @@ public class OperatorConventions {
.put(JetTokens.MINUSEQ, Name.identifier("minusAssign")) .put(JetTokens.MINUSEQ, Name.identifier("minusAssign"))
.build(); .build();
public static final ImmutableMap<JetToken, JetToken> ASSIGNMENT_OPERATION_COUNTERPARTS = ImmutableMap.<JetToken, JetToken>builder() public static final ImmutableBiMap<JetToken, JetToken> ASSIGNMENT_OPERATION_COUNTERPARTS = ImmutableBiMap.<JetToken, JetToken>builder()
.put(JetTokens.MULTEQ, JetTokens.MUL) .put(JetTokens.MULTEQ, JetTokens.MUL)
.put(JetTokens.DIVEQ, JetTokens.DIV) .put(JetTokens.DIVEQ, JetTokens.DIV)
.put(JetTokens.PERCEQ, JetTokens.PERC) .put(JetTokens.PERCEQ, JetTokens.PERC)
@@ -100,7 +103,7 @@ public class OperatorConventions {
.put(JetTokens.ANDAND, Name.identifier("and")) .put(JetTokens.ANDAND, Name.identifier("and"))
.put(JetTokens.OROR, Name.identifier("or")) .put(JetTokens.OROR, Name.identifier("or"))
.build(); .build();
@Nullable @Nullable
public static Name getNameForOperationSymbol(@NotNull JetToken token) { public static Name getNameForOperationSymbol(@NotNull JetToken token) {
Name name = UNARY_OPERATION_NAMES.get(token); Name name = UNARY_OPERATION_NAMES.get(token);
@@ -105,7 +105,7 @@ public interface JetTokens {
JetSingleValueToken EQEQEQ = new JetSingleValueToken("EQEQEQ", "==="); JetSingleValueToken EQEQEQ = new JetSingleValueToken("EQEQEQ", "===");
JetSingleValueToken ARROW = new JetSingleValueToken("ARROW", "->"); JetSingleValueToken ARROW = new JetSingleValueToken("ARROW", "->");
JetSingleValueToken DOUBLE_ARROW = new JetSingleValueToken("DOUBLE_ARROW", "=>"); JetSingleValueToken DOUBLE_ARROW = new JetSingleValueToken("DOUBLE_ARROW", "=>");
JetSingleValueToken EXCLEQEQEQ = new JetSingleValueToken("EXCLEQEQEQ", "!==="); JetSingleValueToken EXCLEQEQEQ = new JetSingleValueToken("EXCLEQEQEQ", "!==");
JetSingleValueToken EQEQ = new JetSingleValueToken("EQEQ", "=="); JetSingleValueToken EQEQ = new JetSingleValueToken("EQEQ", "==");
JetSingleValueToken EXCLEQ = new JetSingleValueToken("EXCLEQ", "!="); JetSingleValueToken EXCLEQ = new JetSingleValueToken("EXCLEQ", "!=");
JetSingleValueToken EXCLEXCL = new JetSingleValueToken("EXCLEXCL", "!!"); JetSingleValueToken EXCLEXCL = new JetSingleValueToken("EXCLEXCL", "!!");
@@ -18,6 +18,7 @@ package org.jetbrains.jet.lang.types.lang;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import kotlin.KotlinPackage;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.PlatformToKotlinClassMap; import org.jetbrains.jet.lang.PlatformToKotlinClassMap;
@@ -881,4 +882,15 @@ public class KotlinBuiltIns {
public JetType getDefaultBound() { public JetType getDefaultBound() {
return getNullableAnyType(); return getNullableAnyType();
} }
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// GET FUNCTION
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@NotNull
public FunctionDescriptor getIdentityEquals() {
return KotlinPackage.first(getBuiltInsPackageFragment().getMemberScope().getFunctions(Name.identifier("identityEquals")));
}
} }
@@ -21,20 +21,13 @@ import com.intellij.lang.findUsages.FindUsagesProvider
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.PsiNamedElement import com.intellij.psi.PsiNamedElement
import org.jetbrains.jet.lang.psi.* 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 { public class JetFindUsagesProvider : FindUsagesProvider {
class JetWordsScanner : DefaultWordsScanner(JetLexer(), TokenSet.create(JetTokens.IDENTIFIER), JetTokens.COMMENTS, JetTokens.STRINGS)
public override fun canFindUsagesFor(psiElement: PsiElement): Boolean = public override fun canFindUsagesFor(psiElement: PsiElement): Boolean =
psiElement is JetNamedDeclaration psiElement is JetNamedDeclaration
public override fun getWordsScanner(): WordsScanner = public override fun getWordsScanner(): WordsScanner =
JetWordsScanner() KotlinWordsScanner()
public override fun getHelpId(psiElement: PsiElement): String? = null public override fun getHelpId(psiElement: PsiElement): String? = null
@@ -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<WordOccurrence>) {
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<WordOccurrence>) {
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()
}
}
}
@@ -20,6 +20,10 @@ import org.jetbrains.jet.lang.psi.JetMultiDeclaration
import org.jetbrains.jet.lang.resolve.BindingContext import org.jetbrains.jet.lang.resolve.BindingContext
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor
import com.intellij.openapi.util.TextRange 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<JetMultiDeclaration>(element) { class JetMultiDeclarationReference(element: JetMultiDeclaration) : JetMultiReference<JetMultiDeclaration>(element) {
override fun getTargetDescriptors(context: BindingContext): Collection<DeclarationDescriptor> { override fun getTargetDescriptors(context: BindingContext): Collection<DeclarationDescriptor> {
@@ -28,14 +32,10 @@ class JetMultiDeclarationReference(element: JetMultiDeclaration) : JetMultiRefer
}.filterNotNull() }.filterNotNull()
} }
override fun getRangeInElement(): TextRange? { override fun getRangeInElement(): TextRange? {
val entries = expression.getEntries() val start = expression.getLPar()
if (entries.isEmpty()) { val end = expression.getRPar()
return TextRange.EMPTY_RANGE if (start == null || end == null) return TextRange.EMPTY_RANGE
} return TextRange(start.getStartOffsetInParent(), end.getStartOffsetInParent())
val start = entries.first!!.getStartOffsetInParent()
val end = entries.last!!.getStartOffsetInParent() + entries.last!!.getTextLength()
return TextRange(start, end)
} }
} }
@@ -28,17 +28,13 @@ import org.jetbrains.jet.lang.resolve.BindingContext
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache
import java.util.Collections import java.util.Collections
import java.util.HashSet import java.util.HashSet
import org.jetbrains.jet.lang.resolve.BindingContextUtils
import org.jetbrains.jet.lang.descriptors.PackageViewDescriptor import org.jetbrains.jet.lang.descriptors.PackageViewDescriptor
import com.intellij.psi.JavaPsiFacade import com.intellij.psi.JavaPsiFacade
import org.jetbrains.jet.lang.psi.JetReferenceExpression import org.jetbrains.jet.lang.psi.JetReferenceExpression
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.jet.plugin.codeInsight.DescriptorToDeclarationUtil import org.jetbrains.jet.plugin.codeInsight.DescriptorToDeclarationUtil
import com.intellij.util.containers.ContainerUtil import com.intellij.util.containers.ContainerUtil
import org.jetbrains.jet.asJava.*
import org.jetbrains.jet.lang.psi.JetElement import org.jetbrains.jet.lang.psi.JetElement
import org.jetbrains.jet.utils.keysToMap import org.jetbrains.jet.utils.keysToMap
import com.intellij.psi.PsiMethod
import org.jetbrains.jet.plugin.search.allScope import org.jetbrains.jet.plugin.search.allScope
import org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils import org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils
@@ -65,20 +61,16 @@ abstract class AbstractJetReference<T : JetElement>(element: T)
return null return null
} }
override fun isReferenceTo(element: PsiElement?): Boolean {
return element != null && matchesTarget(element)
}
override fun getCanonicalText(): String = "<TBD>" override fun getCanonicalText(): String = "<TBD>"
override fun handleElementRename(newElementName: String?): PsiElement? = throw IncorrectOperationException() override fun handleElementRename(newElementName: String?): PsiElement? = throw IncorrectOperationException()
override fun bindToElement(element: PsiElement): 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")] [suppress("CAST_NEVER_SUCCEEDS")]
override fun getVariants(): Array<Any> = PsiReference.EMPTY_ARRAY as Array<Any> override fun getVariants(): Array<Any> = PsiReference.EMPTY_ARRAY as Array<Any>
@@ -152,21 +144,6 @@ public abstract class JetSimpleReference<T : JetReferenceExpression>(expression:
} }
return context[BindingContext.AMBIGUOUS_REFERENCE_TARGET, expression].orEmpty() 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<T : JetElement>(expression: T) : AbstractJetReference<T>(expression) { public abstract class JetMultiReference<T : JetElement>(expression: T) : AbstractJetReference<T>(expression)
override fun isReferenceTo(element: PsiElement?): Boolean {
if (element == null) {
return false
}
return multiResolve(false).map { it.getElement() }.filterNotNull().any { checkElementMatch(it, element) }
}
}
@@ -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<PsiElement>
get() {
fun PsiElement.adjust(): PsiElement? {
val target = unwrapped
return if (target is JetPropertyAccessor) target.getParentByType(javaClass<JetProperty>()) else target
}
return when (this) {
is JetMultiReference<*> -> multiResolve(false).map { it.getElement()?.adjust() }.filterNotNullTo(HashSet<PsiElement>())
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
}
}
@@ -24,11 +24,13 @@ import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.Processor; import com.intellij.util.Processor;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.asJava.AsJavaPackage; import org.jetbrains.jet.asJava.AsJavaPackage;
import org.jetbrains.jet.asJava.LightClassUtil; import org.jetbrains.jet.asJava.LightClassUtil;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.java.jetAsJava.KotlinLightMethod; import org.jetbrains.jet.lang.resolve.java.jetAsJava.KotlinLightMethod;
import org.jetbrains.jet.plugin.JetPluginUtil; import org.jetbrains.jet.plugin.JetPluginUtil;
import org.jetbrains.jet.plugin.search.usagesSearch.*;
public class KotlinReferencesSearcher extends QueryExecutorBase<PsiReference, ReferencesSearch.SearchParameters> { public class KotlinReferencesSearcher extends QueryExecutorBase<PsiReference, ReferencesSearch.SearchParameters> {
public static void processJetClassOrObject( public static void processJetClassOrObject(
@@ -43,20 +45,48 @@ public class KotlinReferencesSearcher extends QueryExecutorBase<PsiReference, Re
} }
}); });
if (lightClass != null) { if (lightClass != null) {
queryParameters.getOptimizer().searchWord(className, queryParameters.getEffectiveSearchScope(), true, lightClass); searchNamedElement(queryParameters, lightClass, className);
} }
} }
} }
@Override @Override
public void processQuery(@NotNull ReferencesSearch.SearchParameters queryParameters, @NotNull Processor<PsiReference> consumer) { public void processQuery(
@NotNull final ReferencesSearch.SearchParameters queryParameters,
@NotNull final Processor<PsiReference> consumer
) {
PsiElement element = queryParameters.getElementToSearch(); PsiElement element = queryParameters.getElementToSearch();
PsiElement unwrappedElement = AsJavaPackage.getUnwrapped(element); final PsiNamedElement unwrappedElement = AsJavaPackage.getNamedUnwrappedElement(element);
if (unwrappedElement == null if (unwrappedElement == null || JetPluginUtil.isKtFileInGradleProjectInWrongFolder(unwrappedElement)) return;
|| !JetPluginUtil.isInSource(unwrappedElement)
|| JetPluginUtil.isKtFileInGradleProjectInWrongFolder(unwrappedElement)) return;
ApplicationManager.getApplication().runReadAction(
new Runnable() {
@Override
public void run() {
KotlinPsiSearchHelper searchHelper = new KotlinPsiSearchHelper(queryParameters.getElementToSearch().getProject());
UsagesSearchTarget<PsiNamedElement> searchTarget = new UsagesSearchTarget<PsiNamedElement>(
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) { if (element instanceof JetClassOrObject) {
processJetClassOrObject((JetClassOrObject) element, queryParameters); processJetClassOrObject((JetClassOrObject) element, queryParameters);
} }
@@ -99,7 +129,10 @@ public class KotlinReferencesSearcher extends QueryExecutorBase<PsiReference, Re
} }
private static void searchNamedElement(ReferencesSearch.SearchParameters queryParameters, PsiNamedElement element) { private static void searchNamedElement(ReferencesSearch.SearchParameters queryParameters, PsiNamedElement element) {
String name = element != null ? element.getName() : null; searchNamedElement(queryParameters, element, element != null ? element.getName() : null);
}
private static void searchNamedElement(ReferencesSearch.SearchParameters queryParameters, PsiNamedElement element, @Nullable String name) {
if (name != null) { if (name != null) {
queryParameters.getOptimizer().searchWord(name, queryParameters.getEffectiveSearchScope(), true, element); queryParameters.getOptimizer().searchWord(name, queryParameters.getEffectiveSearchScope(), true, element);
} }
@@ -0,0 +1,83 @@
/*
* 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.search.usagesSearch
import org.jetbrains.jet.lang.resolve.name.Name
import org.jetbrains.jet.lexer.JetToken
import org.jetbrains.jet.lang.types.expressions.OperatorConventions.*
import com.google.common.collect.ImmutableSet
import org.jetbrains.jet.lexer.JetTokens
import org.jetbrains.jet.lexer.JetSingleValueToken
import java.util.regex.Pattern
public val ALL_SEARCHABLE_OPERATIONS: ImmutableSet<JetToken> = ImmutableSet
.builder<JetToken>()
.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<String> =
ALL_SEARCHABLE_OPERATIONS.map { (it as JetSingleValueToken).getValue() }.toSet()
public val INDEXING_OPERATION_NAMES: ImmutableSet<Name> =
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<JetToken> = ImmutableSet.of(JetTokens.IN_KEYWORD)
public val COMPARISON_OPERATIONS_TO_SEARCH: ImmutableSet<JetToken> = ImmutableSet.of<JetToken>(JetTokens.LT, JetTokens.GT)
public fun Name.getOperationSymbolsToSearch(): Set<JetToken> {
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<JetToken>(JetTokens.LPAR)
ITERATOR_OPERATION_NAME -> return ImmutableSet.of<JetToken>(JetTokens.IN_KEYWORD)
in INDEXING_OPERATION_NAMES -> return ImmutableSet.of<JetToken>(JetTokens.LBRACKET)
}
if (COMPONENT_OPERATION_PATTERN.matcher(asString()).matches()) return ImmutableSet.of<JetToken>(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<JetToken>(binaryOp, assignmentOp) else ImmutableSet.of<JetToken>(binaryOp)
}
val assignmentOp = ASSIGNMENT_OPERATIONS.inverse()[this]
if (assignmentOp != null) return ImmutableSet.of<JetToken>(assignmentOp)
return ImmutableSet.of<JetToken>()
}
@@ -18,8 +18,6 @@ package org.jetbrains.jet.plugin.search.usagesSearch
import com.intellij.psi.PsiReference import com.intellij.psi.PsiReference
import org.jetbrains.jet.lang.psi.JetClassOrObject 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.*
import org.jetbrains.jet.plugin.search.usagesSearch.UsagesSearchFilter.* import org.jetbrains.jet.plugin.search.usagesSearch.UsagesSearchFilter.*
import org.jetbrains.jet.lang.psi.JetProperty import org.jetbrains.jet.lang.psi.JetProperty
@@ -28,34 +26,35 @@ import java.util.Collections
import java.util.ArrayList import java.util.ArrayList
import org.jetbrains.jet.lang.psi.JetNamedDeclaration import org.jetbrains.jet.lang.psi.JetNamedDeclaration
import com.intellij.psi.PsiNamedElement import com.intellij.psi.PsiNamedElement
import com.intellij.openapi.application.ApplicationManager
import org.jetbrains.jet.asJava.LightClassUtil 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.JetParameter
import org.jetbrains.jet.lang.psi.JetPsiUtil 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.asJava.LightClassUtil.PropertyAccessorsPsiMethods
import org.jetbrains.jet.lang.psi.psiUtil.* 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 val isTargetUsage = (PsiReference::matchesTarget).searchFilter
fun JetNamedDeclaration.namesWithAccessors(readable: Boolean = true, writable: Boolean = true): List<String> {
val name = getName()!!
fun PsiNamedElement.getAccessorNames(readable: Boolean = true, writable: Boolean = true): List<String> {
fun PropertyAccessorsPsiMethods.toNameList(): List<String> { fun PropertyAccessorsPsiMethods.toNameList(): List<String> {
val getter = getGetter() val getter = getGetter()
val setter = getSetter() val setter = getSetter()
val result = arrayListOf(name) val result = ArrayList<String>()
if (readable && getter != null) result.add(getter.getName()) if (readable && getter != null) result.add(getter.getName())
if (writable && setter != null) result.add(setter.getName()) if (writable && setter != null) result.add(setter.getName())
return result return result
} }
if (JetPsiUtil.isLocal(this)) return Collections.singletonList(name) if (this !is JetDeclaration || JetPsiUtil.isLocal(this)) return Collections.emptyList()
when (this) { when (this) {
is JetProperty -> 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<String> {
val name = getName()
return when {
name == null || !Name.isValidIdentifier(name) -> Collections.emptyList<String>()
this is JetParameter -> {
if (!hasValOrVarNode()) return Collections.emptyList<String>()
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<String>()
}
else -> Name.identifier(name).getOperationSymbolsToSearch().map { (it as JetSingleValueToken).getValue() }
}
} }
public abstract class UsagesSearchHelper<T : PsiNamedElement> { public abstract class UsagesSearchHelper<T : PsiNamedElement> {
protected open fun makeFilter(target: UsagesSearchTarget<T>): UsagesSearchFilter = isTargetUsage protected open fun makeFilter(target: UsagesSearchTarget<T>): UsagesSearchFilter = isTargetUsage
protected open fun makeWordList(target: UsagesSearchTarget<T>): List<String> { protected open fun makeWordList(target: UsagesSearchTarget<T>): List<String> {
return with(target) { return with(target.element) {
val name = element.getName() ContainerUtil.createMaybeSingletonList(getName()) + getAccessorNames() + getSpecialNamesToSearch()
when {
name == null -> Collections.emptyList<String>()
element is JetProperty, element is JetParameter -> (element as JetNamedDeclaration).namesWithAccessors()
else -> Collections.singletonList(name)
}
} }
} }
@@ -185,7 +195,11 @@ class PropertyUsagesSearchHelper(
skipImports: Boolean = false skipImports: Boolean = false
) : DefaultSearchHelper<JetNamedDeclaration>(skipImports), OverrideSearchHelper { ) : DefaultSearchHelper<JetNamedDeclaration>(skipImports), OverrideSearchHelper {
override fun makeWordList(target: UsagesSearchTarget<JetNamedDeclaration>): List<String> { override fun makeWordList(target: UsagesSearchTarget<JetNamedDeclaration>): List<String> {
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<JetNamedDeclaration>): UsagesSearchFilter { override fun makeFilter(target: UsagesSearchTarget<JetNamedDeclaration>): UsagesSearchFilter {
@@ -19,7 +19,6 @@ package org.jetbrains.jet.plugin.search.usagesSearch
import com.intellij.psi.PsiReference import com.intellij.psi.PsiReference
import com.intellij.util.QueryFactory import com.intellij.util.QueryFactory
import com.intellij.psi.search.SearchScope import com.intellij.psi.search.SearchScope
import com.intellij.psi.PsiElement
import com.intellij.psi.search.SearchRequestCollector import com.intellij.psi.search.SearchRequestCollector
import com.intellij.psi.search.SearchSession import com.intellij.psi.search.SearchSession
import com.intellij.psi.search.PsiSearchHelper import com.intellij.psi.search.PsiSearchHelper
@@ -29,7 +28,6 @@ import com.intellij.psi.search.SearchRequestQuery
import com.intellij.util.UniqueResultsQuery import com.intellij.util.UniqueResultsQuery
import com.intellij.psi.search.searches.ReferenceDescriptor import com.intellij.psi.search.searches.ReferenceDescriptor
import com.intellij.util.containers.ContainerUtil import com.intellij.util.containers.ContainerUtil
import com.intellij.openapi.application.ApplicationManager
import com.intellij.psi.search.UsageSearchContext import com.intellij.psi.search.UsageSearchContext
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.search.RequestResultProcessor import com.intellij.psi.search.RequestResultProcessor
@@ -38,15 +36,22 @@ import com.intellij.openapi.application.QueryExecutorBase
import com.intellij.psi.PsiReferenceService import com.intellij.psi.PsiReferenceService
import com.intellij.openapi.progress.ProgressManager import com.intellij.openapi.progress.ProgressManager
import com.intellij.psi.ReferenceRange 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 com.intellij.openapi.project.Project
import java.util.ArrayDeque
import org.jetbrains.jet.plugin.search.usagesSearch.UsagesSearchFilter.* import org.jetbrains.jet.plugin.search.usagesSearch.UsagesSearchFilter.*
import org.jetbrains.jet.plugin.search.and 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( public data class UsagesSearchLocation(
val inCode: Boolean = true, val inCode: Boolean = true,
@@ -103,39 +108,61 @@ public data class UsagesSearchRequest(val project: Project, val items: List<Usag
val collector: SearchRequestCollector = SearchRequestCollector(SearchSession()) val collector: SearchRequestCollector = SearchRequestCollector(SearchSession())
} }
public object UsagesSearch: QueryFactory<PsiReference, UsagesSearchRequest>() { public class KotlinPsiSearchHelper(private val project: Project): PsiSearchHelperImpl(PsiManager.getInstance(project) as PsiManagerEx) {
{ class ResultTextProcessorImpl(
class ResultProcessorImpl(private val node: UsagesSearchRequestItem) : RequestResultProcessor() { private val node: UsagesSearchRequestItem,
private val referenceService = PsiReferenceService.getService()!! private val consumer: Processor<PsiReference>
): TextOccurenceProcessor {
private val referenceService = PsiReferenceService.getService()!!
override fun processTextOccurrence(element: PsiElement, offsetInElement: Int, consumer: Processor<PsiReference>): Boolean { override fun execute(element: PsiElement, offsetInElement: Int): Boolean {
return referenceService.getReferences(element, PsiReferenceService.Hints.NO_HINTS).all { ref -> return referenceService.getReferences(element, PsiReferenceService.Hints.NO_HINTS).all { ref ->
ProgressManager.checkCanceled() ProgressManager.checkCanceled()
when { when {
!ReferenceRange.containsOffsetInElement(ref, offsetInElement) -> true !ReferenceRange.containsOffsetInElement(ref, offsetInElement) -> true
!node.filter.accepts(ref, node) -> true !node.filter.accepts(ref, node) -> true
else -> consumer.process(ref) else -> consumer.process(ref)
}
} }
} }
} }
}
override fun processFilesWithText(
scope: GlobalSearchScope,
searchContext: Short,
caseSensitively: Boolean,
text: String,
processor: Processor<VirtualFile>
): 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<PsiReference>): 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<PsiReference, UsagesSearchRequest>() {
{
object ExecutorImpl: QueryExecutorBase<PsiReference, UsagesSearchRequest>() { object ExecutorImpl: QueryExecutorBase<PsiReference, UsagesSearchRequest>() {
override fun processQuery(request: UsagesSearchRequest, consumer: Processor<PsiReference>) { override fun processQuery(request: UsagesSearchRequest, consumer: Processor<PsiReference>) {
for (item in request.items) { val searchHelper = KotlinPsiSearchHelper(request.project)
with (item) { request.items.filter { it.filter != False }.all { searchHelper.processFilesWithText(it, consumer) }
if (filter != False) {
ApplicationManager.getApplication()?.runReadAction {
for (word in words) {
request.collector.searchWord(
word, target.scope, target.location.searchContext, true, ResultProcessorImpl(item)
)
}
}
}
}
}
} }
} }
@@ -23,7 +23,6 @@ import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor
import org.jetbrains.jet.lang.psi.* import org.jetbrains.jet.lang.psi.*
import org.jetbrains.jet.lang.psi.psiUtil.* import org.jetbrains.jet.lang.psi.psiUtil.*
import org.jetbrains.jet.lang.resolve.BindingContext import org.jetbrains.jet.lang.resolve.BindingContext
import org.jetbrains.jet.lang.resolve.BindingContextUtils
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache
import com.intellij.psi.PsiReference import com.intellij.psi.PsiReference
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor 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.asJava.unwrapped
import org.jetbrains.jet.lang.resolve.OverrideResolver import org.jetbrains.jet.lang.resolve.OverrideResolver
import org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils import org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils
import com.intellij.util.containers.ContainerUtil
// Navigation element of the resolved reference import org.jetbrains.jet.plugin.references.JetMultiReference
// For property accessor return enclosing property import java.util.HashSet
val PsiReference.unwrappedTarget: PsiElement? import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor
get() { import org.jetbrains.jet.plugin.references.JetReference
val target = resolve()?.unwrapped import com.intellij.psi.PsiMethod
return if (target is JetPropertyAccessor) target.getParentByType(javaClass<JetProperty>()) else target import org.jetbrains.jet.plugin.references.*
}
val JetDeclaration.descriptor: DeclarationDescriptor? val JetDeclaration.descriptor: DeclarationDescriptor?
get() = AnalyzerFacadeWithCache.getContextForElement(this).get(BindingContext.DECLARATION_TO_DESCRIPTOR, this) get() = AnalyzerFacadeWithCache.getContextForElement(this).get(BindingContext.DECLARATION_TO_DESCRIPTOR, this)
@@ -53,21 +51,19 @@ val JetDeclaration.descriptor: DeclarationDescriptor?
val JetParameter.propertyDescriptor: PropertyDescriptor? val JetParameter.propertyDescriptor: PropertyDescriptor?
get() = AnalyzerFacadeWithCache.getContextForElement(this).get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, this) get() = AnalyzerFacadeWithCache.getContextForElement(this).get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, this)
fun PsiReference.isTargetUsage(target: PsiElement): Boolean {
return target.unwrapped == unwrappedTarget
}
fun PsiReference.checkUsageVsOriginalDescriptor( fun PsiReference.checkUsageVsOriginalDescriptor(
target: JetDeclaration, target: JetDeclaration,
declarationToDescriptor: (JetDeclaration) -> DeclarationDescriptor? = {it.descriptor}, declarationToDescriptor: (JetDeclaration) -> DeclarationDescriptor? = {it.descriptor},
checker: (usageDescriptor: DeclarationDescriptor, targetDescriptor: DeclarationDescriptor) -> Boolean checker: (usageDescriptor: DeclarationDescriptor, targetDescriptor: DeclarationDescriptor) -> Boolean
): Boolean { ): Boolean {
val refTarget = unwrappedTarget return unwrappedTargets.any {
if (refTarget !is JetDeclaration) return false if (it is JetDeclaration) {
val usageDescriptor = declarationToDescriptor(it)
val usageDescriptor = declarationToDescriptor(refTarget) val targetDescriptor = declarationToDescriptor(target)
val targetDescriptor = declarationToDescriptor(target) usageDescriptor != null && targetDescriptor != null && checker(usageDescriptor, targetDescriptor)
return usageDescriptor != null && targetDescriptor != null && checker(usageDescriptor, targetDescriptor) }
else false
}
} }
fun PsiReference.isImportUsage(): Boolean = fun PsiReference.isImportUsage(): Boolean =
@@ -0,0 +1,20 @@
// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetNamedFunction
// OPTIONS: usages
class A(val n: Int) {
fun <caret>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
}
@@ -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)
@@ -0,0 +1,11 @@
// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetParameter
// OPTIONS: usages
data class A(val <caret>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
}
@@ -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
@@ -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.<caret>component1()
val (x, y, z) = a
}
@@ -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
@@ -0,0 +1,16 @@
// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetNamedFunction
// OPTIONS: usages
class A(val n: Int) {
fun <caret>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) -> {}
}
}
@@ -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
@@ -0,0 +1,14 @@
// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetNamedFunction
// OPTIONS: usages
class A(val n: Int) {
override fun <caret>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)
}
@@ -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)
@@ -0,0 +1,17 @@
// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetNamedFunction
// OPTIONS: usages
class A<T: Any> {
public fun <caret>iterator(): Iterator<T> = throw IllegalStateException("")
}
class B<T: Any> {
public fun iterator(): Iterator<T> = throw IllegalStateException("")
}
fun test() {
for (a in A<String>()) {}
for (b in B<String>()) {}
for (a in A<Int>()) {}
for (b in B<Int>()) {}
}
@@ -0,0 +1,2 @@
Implicit iteration (13: 12) for (a in A<String>()) {}
Implicit iteration (15: 12) for (a in A<Int>()) {}
@@ -0,0 +1,11 @@
// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetNamedFunction
// OPTIONS: usages
class B(val n: Int) {
fun <caret>get(i: Int): B = B(i)
}
fun test() {
B(1).get(2)
B(1)[2]
}
@@ -0,0 +1,2 @@
Function call (9: 10) B(1).get(2)
Implicit 'get' (10: 5) B(1)[2]
@@ -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) <caret>identityEquals A(1)
A(0) === A(1)
A(0) !== A(1)
}
@@ -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)
@@ -0,0 +1,13 @@
// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetNamedFunction
// OPTIONS: usages
class A(val n: Int) {
fun <caret>inc(): A = A(n + 1)
}
fun test() {
var a = A(1)
a.inc()
++a
a++
}
@@ -0,0 +1,3 @@
Function call (10: 7) a.inc()
Function call (11: 5) ++a
Function call (12: 6) a++
@@ -0,0 +1,11 @@
// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetNamedFunction
// OPTIONS: usages
class B(val n: Int) {
fun <caret>invoke(i: Int): B = B(i)
}
fun test() {
B(1).invoke(2)
B(1)(2)
}
@@ -0,0 +1,2 @@
Function call (9: 10) B(1).invoke(2)
Implicit 'invoke' (10: 5) B(1)(2)
@@ -0,0 +1,19 @@
// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetNamedFunction
// OPTIONS: usages
class A(val n: Int) {
fun <caret>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)
}
@@ -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
@@ -0,0 +1,19 @@
// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetNamedFunction
// OPTIONS: usages
class A(var n: Int) {
fun <caret>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)
}
@@ -0,0 +1,3 @@
Function call (16: 7) a.plusAssign(1)
Function call (10: 14) this += a.n
Function call (17: 7) a += 1
@@ -0,0 +1,13 @@
// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetNamedFunction
// OPTIONS: usages
class B(val n: Int) {
fun <caret>set(i: Int, a: B) {}
}
fun test() {
var a = B(1)
a.set(2, B(2))
a[2] = B(2)
a[2]
}
@@ -0,0 +1,2 @@
Function call (10: 7) a.set(2, B(2))
Implicit 'set' (11: 5) a[2] = B(2)
@@ -0,0 +1,11 @@
// PSI_ELEMENT: org.jetbrains.jet.lang.psi.JetNamedFunction
// OPTIONS: usages
class A(val n: Int) {
fun <caret>minus(): A = this
}
fun test() {
A(1).minus()
-A(1)
}
@@ -0,0 +1,2 @@
Function call (9: 10) A(1).minus()
Function call (10: 5) -A(1)
@@ -33,12 +33,90 @@ import org.jetbrains.jet.findUsages.AbstractJetFindUsagesTest;
@InnerTestClasses({JetFindUsagesTestGenerated.Kotlin.class, JetFindUsagesTestGenerated.Java.class}) @InnerTestClasses({JetFindUsagesTestGenerated.Kotlin.class, JetFindUsagesTestGenerated.Java.class})
public class JetFindUsagesTestGenerated extends AbstractJetFindUsagesTest { public class JetFindUsagesTestGenerated extends AbstractJetFindUsagesTest {
@TestMetadata("idea/testData/findUsages/kotlin") @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 static class Kotlin extends AbstractJetFindUsagesTest {
public void testAllFilesPresentInKotlin() throws Exception { 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); 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") @TestMetadata("idea/testData/findUsages/kotlin/findClassUsages")
public static class FindClassUsages extends AbstractJetFindUsagesTest { public static class FindClassUsages extends AbstractJetFindUsagesTest {
public void testAllFilesPresentInFindClassUsages() throws Exception { public void testAllFilesPresentInFindClassUsages() throws Exception {
@@ -597,6 +675,7 @@ public class JetFindUsagesTestGenerated extends AbstractJetFindUsagesTest {
public static Test innerSuite() { public static Test innerSuite() {
TestSuite suite = new TestSuite("Kotlin"); TestSuite suite = new TestSuite("Kotlin");
suite.addTestSuite(Kotlin.class); suite.addTestSuite(Kotlin.class);
suite.addTestSuite(Conventions.class);
suite.addTestSuite(FindClassUsages.class); suite.addTestSuite(FindClassUsages.class);
suite.addTestSuite(FindFunctionUsages.class); suite.addTestSuite(FindFunctionUsages.class);
suite.addTestSuite(FindObjectUsages.class); suite.addTestSuite(FindObjectUsages.class);