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

View File

@@ -1,4 +1,29 @@
<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...)'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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);
}
}

View File

@@ -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);

View File

@@ -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<JetToken> EQUALS_OPERATIONS =
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 =
ImmutableSet.<JetToken>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<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.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);

View File

@@ -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", "!!");

View File

@@ -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")));
}
}

View File

@@ -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

View File

@@ -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()
}
}
}

View File

@@ -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<JetMultiDeclaration>(element) {
override fun getTargetDescriptors(context: BindingContext): Collection<DeclarationDescriptor> {
@@ -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())
}
}

View File

@@ -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<T : JetElement>(element: T)
return null
}
override fun isReferenceTo(element: PsiElement?): Boolean {
return element != null && matchesTarget(element)
}
override fun getCanonicalText(): String = "<TBD>"
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<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()
}
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) {
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<T : JetElement>(expression: T) : AbstractJetReference<T>(expression)

View File

@@ -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
}
}

View File

@@ -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<PsiReference, ReferencesSearch.SearchParameters> {
public static void processJetClassOrObject(
@@ -43,20 +45,48 @@ public class KotlinReferencesSearcher extends QueryExecutorBase<PsiReference, Re
}
});
if (lightClass != null) {
queryParameters.getOptimizer().searchWord(className, queryParameters.getEffectiveSearchScope(), true, lightClass);
searchNamedElement(queryParameters, lightClass, className);
}
}
}
@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 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<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) {
processJetClassOrObject((JetClassOrObject) element, queryParameters);
}
@@ -99,7 +129,10 @@ public class KotlinReferencesSearcher extends QueryExecutorBase<PsiReference, Re
}
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) {
queryParameters.getOptimizer().searchWord(name, queryParameters.getEffectiveSearchScope(), true, element);
}

View File

@@ -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>()
}

View File

@@ -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<String> {
val name = getName()!!
val isTargetUsage = (PsiReference::matchesTarget).searchFilter
fun PsiNamedElement.getAccessorNames(readable: Boolean = true, writable: Boolean = true): List<String> {
fun PropertyAccessorsPsiMethods.toNameList(): List<String> {
val getter = getGetter()
val setter = getSetter()
val result = arrayListOf(name)
val result = ArrayList<String>()
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<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> {
protected open fun makeFilter(target: UsagesSearchTarget<T>): UsagesSearchFilter = isTargetUsage
protected open fun makeWordList(target: UsagesSearchTarget<T>): List<String> {
return with(target) {
val name = element.getName()
when {
name == null -> Collections.emptyList<String>()
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<JetNamedDeclaration>(skipImports), OverrideSearchHelper {
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 {

View File

@@ -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<Usag
val collector: SearchRequestCollector = SearchRequestCollector(SearchSession())
}
public object UsagesSearch: QueryFactory<PsiReference, UsagesSearchRequest>() {
{
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<PsiReference>
): TextOccurenceProcessor {
private val referenceService = PsiReferenceService.getService()!!
override fun processTextOccurrence(element: PsiElement, offsetInElement: Int, consumer: Processor<PsiReference>): 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<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>() {
override fun processQuery(request: UsagesSearchRequest, consumer: Processor<PsiReference>) {
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) }
}
}

View File

@@ -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<JetProperty>()) 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 =

View File

@@ -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
}

View File

@@ -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)

View File

@@ -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
}

View File

@@ -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

View File

@@ -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
}

View File

@@ -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

View File

@@ -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) -> {}
}
}

View File

@@ -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

View File

@@ -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)
}

View File

@@ -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)

View File

@@ -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>()) {}
}

View File

@@ -0,0 +1,2 @@
Implicit iteration (13: 12) for (a in A<String>()) {}
Implicit iteration (15: 12) for (a in A<Int>()) {}

View File

@@ -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]
}

View File

@@ -0,0 +1,2 @@
Function call (9: 10) B(1).get(2)
Implicit 'get' (10: 5) B(1)[2]

View File

@@ -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)
}

View File

@@ -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)

View File

@@ -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++
}

View File

@@ -0,0 +1,3 @@
Function call (10: 7) a.inc()
Function call (11: 5) ++a
Function call (12: 6) a++

View File

@@ -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)
}

View File

@@ -0,0 +1,2 @@
Function call (9: 10) B(1).invoke(2)
Implicit 'invoke' (10: 5) B(1)(2)

View File

@@ -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)
}

View File

@@ -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

View File

@@ -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)
}

View File

@@ -0,0 +1,3 @@
Function call (16: 7) a.plusAssign(1)
Function call (10: 14) this += a.n
Function call (17: 7) a += 1

View File

@@ -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]
}

View File

@@ -0,0 +1,2 @@
Function call (10: 7) a.set(2, B(2))
Implicit 'set' (11: 5) a[2] = B(2)

View File

@@ -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)
}

View File

@@ -0,0 +1,2 @@
Function call (9: 10) A(1).minus()
Function call (10: 5) -A(1)

View File

@@ -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);