Supported "count()"
This commit is contained in:
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.idea.analysis.analyzeInContext
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.intentions.loopToCallChain.result.AddToCollectionTransformation
|
||||
import org.jetbrains.kotlin.idea.intentions.loopToCallChain.result.CountTransformation
|
||||
import org.jetbrains.kotlin.idea.intentions.loopToCallChain.result.FindAndAssignTransformation
|
||||
import org.jetbrains.kotlin.idea.intentions.loopToCallChain.result.FindAndReturnTransformation
|
||||
import org.jetbrains.kotlin.idea.intentions.loopToCallChain.sequence.FilterTransformation
|
||||
@@ -48,7 +49,8 @@ object MatcherRegistrar {
|
||||
val resultMatchers: Collection<ResultTransformationMatcher> = listOf(
|
||||
FindAndReturnTransformation.Matcher,
|
||||
FindAndAssignTransformation.Matcher,
|
||||
AddToCollectionTransformation.Matcher
|
||||
AddToCollectionTransformation.Matcher,
|
||||
CountTransformation.Matcher
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.intentions.loopToCallChain.result
|
||||
|
||||
import com.intellij.psi.search.LocalSearchScope
|
||||
import com.intellij.psi.search.searches.ReferencesSearch
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||
import org.jetbrains.kotlin.idea.intentions.loopToCallChain.*
|
||||
import org.jetbrains.kotlin.idea.intentions.loopToCallChain.sequence.FilterTransformation
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
|
||||
class CountTransformation(
|
||||
loop: KtForExpression,
|
||||
inputVariable: KtCallableDeclaration,
|
||||
initialization: VariableInitialization,
|
||||
private val filter: KtExpression?
|
||||
) : AssignToVariableResultTransformation(loop, inputVariable, initialization) {
|
||||
|
||||
override fun mergeWithPrevious(previousTransformation: SequenceTransformation): ResultTransformation? {
|
||||
if (previousTransformation !is FilterTransformation) return null
|
||||
assert(filter == null) { "Should not happen because no 2 consecutive FilterTransformation's possible"}
|
||||
return CountTransformation(loop, previousTransformation.inputVariable, initialization, previousTransformation.effectiveCondition())
|
||||
}
|
||||
|
||||
override val presentation: String
|
||||
get() = "count" + (if (filter != null) "{}" else "()")
|
||||
|
||||
override fun generateCode(chainedCallGenerator: ChainedCallGenerator): KtExpression {
|
||||
val call = if (filter != null) {
|
||||
val lambda = generateLambda(inputVariable, filter)
|
||||
chainedCallGenerator.generate("count $0:'{}'", lambda)
|
||||
}
|
||||
else {
|
||||
chainedCallGenerator.generate("count()")
|
||||
}
|
||||
|
||||
if ((initialization.initializer as? KtConstantExpression)?.text == "0") {
|
||||
return call
|
||||
}
|
||||
else {
|
||||
return KtPsiFactory(call).createExpressionByPattern("$0 + $1", initialization.initializer, call)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches:
|
||||
* val variable = 0
|
||||
* for (...) {
|
||||
* ...
|
||||
* variable++ (or ++variable)
|
||||
* }
|
||||
*/
|
||||
object Matcher : ResultTransformationMatcher {
|
||||
override fun match(state: MatchingState): ResultTransformationMatch? {
|
||||
val statement = state.statements.singleOrNull() as? KtUnaryExpression ?: return null
|
||||
if (statement.operationToken != KtTokens.PLUSPLUS) return null
|
||||
|
||||
val operand = statement.baseExpression
|
||||
val initialization = operand?.detectInitializationBeforeLoop(state.outerLoop) ?: return null
|
||||
|
||||
val usageCountInLoop = ReferencesSearch.search(initialization.variable, LocalSearchScope(state.outerLoop)).count()
|
||||
if (usageCountInLoop != 1) return null // this should be the only usage of this variable inside the loop
|
||||
|
||||
val variableType = (initialization.variable.resolveToDescriptorIfAny() as? VariableDescriptor)?.type ?: return null
|
||||
if (!KotlinBuiltIns.isInt(variableType)) return null
|
||||
|
||||
val transformation = CountTransformation(state.outerLoop, state.inputVariable, initialization, null)
|
||||
return ResultTransformationMatch(transformation)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// WITH_RUNTIME
|
||||
// INTENTION_TEXT: "Replace with 'count{}'"
|
||||
fun foo(list: List<String>): Int {
|
||||
var count = 0
|
||||
<caret>for (s in list) {
|
||||
if (s.isNotBlank()) {
|
||||
count++
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// WITH_RUNTIME
|
||||
// INTENTION_TEXT: "Replace with 'count{}'"
|
||||
fun foo(list: List<String>): Int {
|
||||
<caret>val count = list.count { it.isNotBlank() }
|
||||
return count
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// WITH_RUNTIME
|
||||
// INTENTION_TEXT: "Replace with 'count()'"
|
||||
fun foo(list: Iterable<String>): Int {
|
||||
var count = 0
|
||||
<caret>for (s in list) {
|
||||
count++
|
||||
}
|
||||
return count
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// WITH_RUNTIME
|
||||
// INTENTION_TEXT: "Replace with 'count()'"
|
||||
fun foo(list: Iterable<String>): Int {
|
||||
<caret>val count = list.count()
|
||||
return count
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// WITH_RUNTIME
|
||||
// IS_APPLICABLE: false
|
||||
fun foo(list: List<String>): Long {
|
||||
var count = 0L
|
||||
<caret>for (s in list) {
|
||||
if (s.length > 10) {
|
||||
count++
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// WITH_RUNTIME
|
||||
// INTENTION_TEXT: "Replace with 'count{}'"
|
||||
fun foo(list: List<String>): Int {
|
||||
var count = bar()
|
||||
<caret>for (s in list) {
|
||||
if (s.isNotBlank()) {
|
||||
count++
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
fun bar(): Int = 0
|
||||
@@ -0,0 +1,8 @@
|
||||
// WITH_RUNTIME
|
||||
// INTENTION_TEXT: "Replace with 'count{}'"
|
||||
fun foo(list: List<String>): Int {
|
||||
<caret>val count = bar() + list.count { it.isNotBlank() }
|
||||
return count
|
||||
}
|
||||
|
||||
fun bar(): Int = 0
|
||||
@@ -0,0 +1,11 @@
|
||||
// WITH_RUNTIME
|
||||
// INTENTION_TEXT: "Replace with 'count{}'"
|
||||
fun foo(list: List<String>): Int {
|
||||
var count = 1
|
||||
<caret>for (s in list) {
|
||||
if (s.isNotBlank()) {
|
||||
count++
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// WITH_RUNTIME
|
||||
// INTENTION_TEXT: "Replace with 'count{}'"
|
||||
fun foo(list: List<String>): Int {
|
||||
<caret>val count = 1 + list.count { it.isNotBlank() }
|
||||
return count
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// WITH_RUNTIME
|
||||
// INTENTION_TEXT: "Replace with 'count{}'"
|
||||
fun foo(list: List<String>): Int {
|
||||
var count = 0
|
||||
<caret>for (s in list) {
|
||||
if (s.isNotBlank()) {
|
||||
++count
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// WITH_RUNTIME
|
||||
// INTENTION_TEXT: "Replace with 'count{}'"
|
||||
fun foo(list: List<String>): Int {
|
||||
<caret>val count = list.count { it.isNotBlank() }
|
||||
return count
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// WITH_RUNTIME
|
||||
// IS_APPLICABLE: false
|
||||
fun foo(list: List<String>): Int {
|
||||
var count = 0
|
||||
<caret>for (s in list) {
|
||||
if (s.length > count) {
|
||||
count++
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
Reference in New Issue
Block a user