KT-7730 Find Usages causes 100% CPU usage, UI blocked, never returned
KT-7623 Renaming val constructor parameter of a data class is very slow #KT-7730 fixed #KT-7730 fixed
This commit is contained in:
+1
-2
@@ -26,8 +26,7 @@ public class JetFindUsagesProvider : FindUsagesProvider {
|
||||
public override fun canFindUsagesFor(psiElement: PsiElement): Boolean =
|
||||
psiElement is JetNamedDeclaration
|
||||
|
||||
public override fun getWordsScanner(): WordsScanner =
|
||||
KotlinWordsScanner()
|
||||
public override fun getWordsScanner() = null
|
||||
|
||||
public override fun getHelpId(psiElement: PsiElement): String? = null
|
||||
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.kotlin.idea.findUsages
|
||||
|
||||
import org.jetbrains.kotlin.idea.search.usagesSearch.*
|
||||
import com.intellij.lang.cacheBuilder.WordsScanner
|
||||
import com.intellij.util.Processor
|
||||
import org.jetbrains.kotlin.lexer.JetLexer
|
||||
import com.intellij.lang.cacheBuilder.WordOccurrence
|
||||
import org.jetbrains.kotlin.lexer.JetTokens
|
||||
import com.intellij.lang.cacheBuilder.SimpleWordsScanner
|
||||
|
||||
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)
|
||||
var valOrVarBefore: Boolean = false
|
||||
|
||||
stream { lexer.getTokenType() }.forEach { elementType ->
|
||||
// todo: replace with when
|
||||
if (ALL_SEARCHABLE_OPERATIONS.contains(elementType) || (valOrVarBefore && elementType == JetTokens.LPAR)) {
|
||||
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)
|
||||
|
||||
if (elementType !in JetTokens.WHITE_SPACE_OR_COMMENT_BIT_SET) {
|
||||
valOrVarBefore = elementType == JetTokens.VAL_KEYWORD || elementType == JetTokens.VAR_KEYWORD
|
||||
}
|
||||
|
||||
lexer.advance()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,11 +24,13 @@ import com.intellij.psi.impl.cache.impl.OccurrenceConsumer
|
||||
import com.intellij.psi.impl.cache.impl.id.LexerBasedIdIndexer
|
||||
import com.intellij.psi.impl.cache.impl.todo.LexerBasedTodoIndexer
|
||||
import com.intellij.psi.search.UsageSearchContext
|
||||
import com.intellij.psi.tree.IElementType
|
||||
import com.intellij.psi.tree.TokenSet
|
||||
import org.jetbrains.kotlin.idea.search.usagesSearch.ALL_SEARCHABLE_OPERATIONS
|
||||
import org.jetbrains.kotlin.kdoc.lexer.KDocTokens
|
||||
import org.jetbrains.kotlin.lexer.JetLexer
|
||||
import org.jetbrains.kotlin.lexer.JetTokens
|
||||
import java.util.*
|
||||
|
||||
class KotlinFilterLexer(table: OccurrenceConsumer): BaseFilterLexer(JetLexer(), table) {
|
||||
private val codeTokens = TokenSet.orSet(
|
||||
@@ -43,11 +45,19 @@ class KotlinFilterLexer(table: OccurrenceConsumer): BaseFilterLexer(JetLexer(),
|
||||
JetTokens.RBRACKET, JetTokens.SEMICOLON, JetTokens.COMMA, JetTokens.DOT
|
||||
)
|
||||
|
||||
private var previousTokens = LinkedList<IElementType>()
|
||||
|
||||
override fun advance() {
|
||||
fun isMultiDeclarationPosition(): Boolean {
|
||||
return previousTokens[0] == JetTokens.VAL_KEYWORD || previousTokens[0] == JetTokens.VAR_KEYWORD
|
||||
|| previousTokens[0] == JetTokens.LPAR && previousTokens[1] == JetTokens.FOR_KEYWORD
|
||||
}
|
||||
|
||||
val tokenType = myDelegate.getTokenType()
|
||||
|
||||
when(tokenType) {
|
||||
when (tokenType) {
|
||||
in codeTokens -> addOccurrenceInToken(UsageSearchContext.IN_CODE.toInt())
|
||||
JetTokens.LPAR -> if (isMultiDeclarationPosition()) addOccurrenceInToken(UsageSearchContext.IN_CODE.toInt())
|
||||
in JetTokens.STRINGS -> scanWordsInToken(UsageSearchContext.IN_STRINGS + UsageSearchContext.IN_FOREIGN_LANGUAGES, false, true)
|
||||
in commentTokens -> {
|
||||
scanWordsInToken(UsageSearchContext.IN_COMMENTS.toInt(), false, false)
|
||||
@@ -56,6 +66,14 @@ class KotlinFilterLexer(table: OccurrenceConsumer): BaseFilterLexer(JetLexer(),
|
||||
!in skipTokens -> scanWordsInToken(UsageSearchContext.IN_PLAIN_TEXT.toInt(), false, false)
|
||||
}
|
||||
|
||||
if (tokenType != TokenType.WHITE_SPACE) {
|
||||
previousTokens.addFirst(tokenType)
|
||||
|
||||
if (previousTokens.size() > 2) {
|
||||
previousTokens.removeLast()
|
||||
}
|
||||
}
|
||||
|
||||
myDelegate.advance()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@ public val ALL_SEARCHABLE_OPERATIONS: ImmutableSet<JetToken> = ImmutableSet
|
||||
.addAll(IDENTITY_EQUALS_OPERATIONS)
|
||||
.addAll(IN_OPERATIONS)
|
||||
.add(JetTokens.LBRACKET)
|
||||
.add(JetTokens.LPAR)
|
||||
.add(JetTokens.BY_KEYWORD)
|
||||
.build()
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
fun test() {
|
||||
for ((x, y, z) in array<A>()) {
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
Function call (9: 7) a.component1()
|
||||
Value read (10: 9) val (x, y, z) = a
|
||||
Value read (2: 10) for ((x, y, z) in array<A>()) {
|
||||
Value read (8: 7) a.n
|
||||
Reference in New Issue
Block a user