Find Usages: Add support of naming conventions
#KT-1356 Fixed
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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.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())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
+40
-7
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 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 {
|
||||
|
||||
@@ -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) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 =
|
||||
|
||||
Reference in New Issue
Block a user