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:
Evgeny Gerashchenko
2015-05-20 21:04:47 +03:00
parent d8745b3ecb
commit e50de5d94d
6 changed files with 25 additions and 66 deletions
@@ -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