KT-41538 Use matchOptionally for [0,0] count filters

This commit is contained in:
Louis Vignier
2020-09-01 21:23:06 +02:00
parent a698e26584
commit bee844ad7c
7 changed files with 36 additions and 34 deletions

View File

@@ -302,18 +302,6 @@ class KotlinCompilingVisitor(private val myCompilingVisitor: GlobalCompilingVisi
constructor.setAbsenceOfMatchHandlerIfApplicable()
}
override fun visitSuperTypeList(list: KtSuperTypeList) {
super.visitSuperTypeList(list)
list.setAbsenceOfMatchHandlerIfApplicable()
}
override fun visitConstructorCalleeExpression(constructorCalleeExpression: KtConstructorCalleeExpression) {
super.visitConstructorCalleeExpression(constructorCalleeExpression)
if (constructorCalleeExpression.allowsAbsenceOfMatch) {
setHandler(constructorCalleeExpression.parent, absenceOfMatchHandler(constructorCalleeExpression))
}
}
override fun visitWhenEntry(jetWhenEntry: KtWhenEntry) {
super.visitWhenEntry(jetWhenEntry)
val condition = jetWhenEntry.firstChild.firstChild
@@ -328,6 +316,23 @@ class KotlinCompilingVisitor(private val myCompilingVisitor: GlobalCompilingVisi
}
}
override fun visitConstructorCalleeExpression(expression: KtConstructorCalleeExpression) {
super.visitConstructorCalleeExpression(expression)
val handler = getHandler(expression)
if (handler is SubstitutionHandler && handler.minOccurs == 0) {
setHandler(expression.parent, SubstitutionHandler("${expression.parent.hashCode()}_optional", false, 0, handler.maxOccurs, false))
expression.parent.parent.setAbsenceOfMatchHandlerIfApplicable()
}
}
// override fun visitSuperTypeEntry(specifier: KtSuperTypeEntry) {
// super.visitSuperTypeEntry(specifier)
// if (specifier.allowsAbsenceOfMatch) {
// specifier.parent.setAbsenceOfMatchHandler()
// specifier.parent.parent.setAbsenceOfMatchHandlerIfApplicable()
// }
// }
override fun visitKDoc(kDoc: KDoc) {
getHandler(kDoc).setFilter { it is KDoc }
}
@@ -340,12 +345,16 @@ class KotlinCompilingVisitor(private val myCompilingVisitor: GlobalCompilingVisi
getHandler(tag).setFilter { it is KDocTag }
}
private fun PsiElement.setAbsenceOfMatchHandler() {
setHandler(this, absenceOfMatchHandler(this))
}
private fun PsiElement.setAbsenceOfMatchHandlerIfApplicable(considerAllChildren: Boolean = false) {
val childrenAllowAbsenceOfMatch =
if (considerAllChildren) this.allChildren.all { it.allowsAbsenceOfMatch }
else this.children.all { it.allowsAbsenceOfMatch }
if (childrenAllowAbsenceOfMatch)
setHandler(this, absenceOfMatchHandler(this))
setAbsenceOfMatchHandler()
}
private fun absenceOfMatchHandler(element: PsiElement): SubstitutionHandler =

View File

@@ -295,10 +295,6 @@ class KotlinMatchingVisitor(private val myMatchingVisitor: GlobalMatchingVisitor
)
val handler = getHandler(expression.getReferencedNameElement())
if (myMatchingVisitor.result && handler is SubstitutionHandler) {
if (handler.maxOccurs == 0) {
myMatchingVisitor.result = false
return
}
handler.handle(
if (other is KtSimpleNameExpression) other.getReferencedNameElement() else other,
myMatchingVisitor.matchContext
@@ -427,12 +423,9 @@ class KotlinMatchingVisitor(private val myMatchingVisitor: GlobalMatchingVisitor
override fun visitDotQualifiedExpression(expression: KtDotQualifiedExpression) {
val other = getTreeElementDepar<KtExpression>() ?: return
val handler = getHandler(expression.receiverExpression)
if (other is KtDotQualifiedExpression && handler is SubstitutionHandler && handler.maxOccurs == 0) {
// Don't match '_{0,0}.'_
myMatchingVisitor.result = false
} else if (other is KtDotQualifiedExpression) {
if (other is KtDotQualifiedExpression) {
// Regular matching
myMatchingVisitor.result = myMatchingVisitor.match(expression.receiverExpression, other.receiverExpression)
myMatchingVisitor.result = myMatchingVisitor.matchOptionally(expression.receiverExpression, other.receiverExpression)
&& myMatchingVisitor.match(expression.selectorExpression, other.selectorExpression)
} else {
// Match '_?.'_
@@ -608,7 +601,7 @@ class KotlinMatchingVisitor(private val myMatchingVisitor: GlobalMatchingVisitor
override fun visitCallableReferenceExpression(expression: KtCallableReferenceExpression) {
val other = getTreeElementDepar<KtCallableReferenceExpression>() ?: return
myMatchingVisitor.result = myMatchingVisitor.match(expression.callableReference, other.callableReference)
&& myMatchingVisitor.match(expression.receiverExpression, other.receiverExpression)
&& myMatchingVisitor.matchOptionally(expression.receiverExpression, other.receiverExpression)
}
override fun visitTypeParameter(parameter: KtTypeParameter) {
@@ -1018,7 +1011,7 @@ class KotlinMatchingVisitor(private val myMatchingVisitor: GlobalMatchingVisitor
&& matchTextOrVariable(property.nameIdentifier, other.nameIdentifier)
&& property.isVar == other.isVar
&& myMatchingVisitor.match(property.docComment, other.docComment)
&& myMatchingVisitor.match(
&& myMatchingVisitor.matchOptionally(
property.delegateExpressionOrInitializer,
other.delegateExpressionOrInitializer
)

View File

@@ -7,19 +7,19 @@ class KotlinSSCountFilterTest : KotlinSSResourceInspectionTest() {
// isApplicableMinCount
fun testMinProperty() { doTest("var '_ = '_?") }
fun testMinProperty() { doTest("var '_ = '_{0,0}") }
fun testMinDotQualifierExpression() { doTest("'_?.'_") }
fun testMinDotQualifierExpression() { doTest("'_{0,0}.'_") }
fun testMinFunctionTypeReference() { doTest("fun '_{0,0}.'_()") }
fun testMinCallableReferenceExpression() { doTest("'_{0,0}::'_") }
fun testMinWhenExpression() { doTest("when ('_?) {}") }
fun testMinWhenExpression() { doTest("when ('_{0,0}) {}") }
fun testMinConstructorCallee() { doTest("class '_ : '_?('_*)") }
fun testMinConstructorCallee() { doTest("class '_ : '_{0,0}('_*)") }
fun testMinSuperType() { doTest("class '_ : '_?()") }
fun testMinSuperType() { doTest("class '_ : '_{0,0}()") }
// isApplicableMaxCount

View File

@@ -1,3 +1,3 @@
<warning descr="SSR">open class Foo</warning>
<warning descr="SSR">class Bar: Foo()</warning>
class Bar: Foo()

View File

@@ -5,7 +5,7 @@ class A {
}
fun main() {
val a = <warning descr="SSR">A.FOO</warning>
<warning descr="SSR">print(<warning descr="SSR">Int.hashCode()</warning>)</warning>
val a = A.FOO
<warning descr="SSR">print(Int.hashCode())</warning>
<warning descr="SSR">print(<warning descr="SSR">a</warning>)</warning>
}

View File

@@ -1,6 +1,6 @@
class A {
<warning descr="SSR">lateinit var x: String</warning>
<warning descr="SSR">var y = 1</warning>
var y = 1
fun init() { x = "a" }
}

View File

@@ -1,2 +1,2 @@
<warning descr="SSR">open class A</warning>
<warning descr="SSR">class B : A()</warning>
class B : A()