PSI Pattern Matching: Add support of weak matching

This commit is contained in:
Alexey Sedunov
2014-09-16 15:26:16 +04:00
parent 07a257b1fe
commit 03e2b4d516
@@ -53,7 +53,6 @@ import org.jetbrains.jet.lang.psi.JetLabelReferenceExpression
import org.jetbrains.jet.lang.resolve.calls.callUtil.getCall import org.jetbrains.jet.lang.resolve.calls.callUtil.getCall
import org.jetbrains.jet.lang.resolve.calls.callUtil.getResolvedCall import org.jetbrains.jet.lang.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.jet.lang.psi.JetDeclaration import org.jetbrains.jet.lang.psi.JetDeclaration
import org.jetbrains.jet.lang.psi.JetNamedDeclaration
import org.jetbrains.jet.lang.types.ErrorUtils import org.jetbrains.jet.lang.types.ErrorUtils
import com.intellij.lang.ASTNode import com.intellij.lang.ASTNode
import com.intellij.util.containers.MultiMap import com.intellij.util.containers.MultiMap
@@ -63,38 +62,30 @@ import org.jetbrains.jet.lang.resolve.scopes.receivers.ThisReceiver
import org.jetbrains.jet.lang.psi.JetThisExpression import org.jetbrains.jet.lang.psi.JetThisExpression
import org.jetbrains.jet.lang.psi.JetStringTemplateEntryWithExpression import org.jetbrains.jet.lang.psi.JetStringTemplateEntryWithExpression
import org.jetbrains.jet.plugin.util.psi.patternMatching.JetPsiRange.Empty import org.jetbrains.jet.plugin.util.psi.patternMatching.JetPsiRange.Empty
import org.jetbrains.jet.lang.psi.JetFunctionLiteral
import org.jetbrains.jet.lang.descriptors.impl.AnonymousFunctionDescriptor
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor
import org.jetbrains.jet.lang.psi.JetMultiDeclaration import org.jetbrains.jet.lang.psi.JetMultiDeclaration
import org.jetbrains.jet.lang.psi.JetFunction import org.jetbrains.jet.lang.psi.JetFunction
import org.jetbrains.jet.lang.psi.JetClassBody import org.jetbrains.jet.lang.psi.JetClassBody
import org.jetbrains.jet.lang.descriptors.CallableDescriptor import org.jetbrains.jet.lang.descriptors.CallableDescriptor
import org.jetbrains.jet.lang.psi.JetDeclarationWithBody import org.jetbrains.jet.lang.psi.JetDeclarationWithBody
import org.jetbrains.jet.lang.psi.JetProperty
import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor
import org.jetbrains.jet.lang.psi.JetWithExpressionInitializer import org.jetbrains.jet.lang.psi.JetWithExpressionInitializer
import org.jetbrains.jet.lang.psi.JetPropertyAccessor
import org.jetbrains.jet.lang.psi.JetMultiDeclarationEntry
import org.jetbrains.jet.lang.psi.JetParameter import org.jetbrains.jet.lang.psi.JetParameter
import org.jetbrains.jet.lang.descriptors.ClassDescriptor import org.jetbrains.jet.lang.descriptors.ClassDescriptor
import org.jetbrains.jet.lang.psi.JetClassOrObject import org.jetbrains.jet.lang.psi.JetClassOrObject
import org.jetbrains.jet.lang.psi.JetCallableDeclaration import org.jetbrains.jet.lang.psi.JetCallableDeclaration
import org.jetbrains.jet.lang.psi.JetClassObject import org.jetbrains.jet.lang.psi.JetClassObject
import org.jetbrains.jet.lang.descriptors.ClassKind
import org.jetbrains.jet.lang.psi.JetTypeParameter import org.jetbrains.jet.lang.psi.JetTypeParameter
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor
import org.jetbrains.jet.lang.types.fqName
import org.jetbrains.jet.renderer.DescriptorRenderer import org.jetbrains.jet.renderer.DescriptorRenderer
import org.jetbrains.jet.plugin.codeInsight.DescriptorToDeclarationUtil
import org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils import org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils
import org.jetbrains.jet.lang.psi.JetClass import org.jetbrains.jet.lang.psi.JetClass
import org.jetbrains.jet.lang.descriptors.VariableDescriptor import org.jetbrains.jet.lang.descriptors.VariableDescriptor
import org.jetbrains.jet.lang.psi.JetFile import org.jetbrains.jet.lang.psi.JetFile
import org.jetbrains.jet.lang.psi.JetClassInitializer import org.jetbrains.jet.lang.psi.JetClassInitializer
import java.util.ArrayList
import org.jetbrains.jet.lang.psi.JetTypeParameterListOwner import org.jetbrains.jet.lang.psi.JetTypeParameterListOwner
import org.jetbrains.jet.lang.psi.doNotAnalyze import org.jetbrains.jet.lang.psi.doNotAnalyze
import org.jetbrains.jet.lang.psi.JetReturnExpression
import org.jetbrains.jet.lang.psi.JetProperty
import org.jetbrains.jet.lang.psi.JetDelegatorToSuperClass import org.jetbrains.jet.lang.psi.JetDelegatorToSuperClass
import org.jetbrains.jet.lang.psi.JetDelegationSpecifier import org.jetbrains.jet.lang.psi.JetDelegationSpecifier
@@ -115,10 +106,18 @@ public trait UnificationResult {
override val status: Status get() = UNMATCHED override val status: Status get() = UNMATCHED
} }
public class Matched(val substitution: Map<UnifierParameter, JetExpression>): UnificationResult { trait Matched: UnificationResult {
val substitution: Map<UnifierParameter, JetExpression>
override val status: Status get() = MATCHED override val status: Status get() = MATCHED
} }
class StronglyMatched(override val substitution: Map<UnifierParameter, JetExpression>): Matched
class WeaklyMatched(
override val substitution: Map<UnifierParameter, JetExpression>,
val weakMatches: Map<JetElement, JetElement>
): Matched
val status: Status val status: Status
val matched: Boolean get() = status != UNMATCHED val matched: Boolean get() = status != UNMATCHED
} }
@@ -129,7 +128,8 @@ public class UnifierParameter(
) )
public class JetPsiUnifier( public class JetPsiUnifier(
parameters: Collection<UnifierParameter> = Collections.emptySet() parameters: Collection<UnifierParameter> = Collections.emptySet(),
val allowWeakMatches: Boolean = false
) { ) {
class object { class object {
val DEFAULT = JetPsiUnifier() val DEFAULT = JetPsiUnifier()
@@ -141,6 +141,7 @@ public class JetPsiUnifier(
) { ) {
val substitution = HashMap<UnifierParameter, JetExpression>() val substitution = HashMap<UnifierParameter, JetExpression>()
val declarationPatternsToTargets = MultiMap<DeclarationDescriptor, DeclarationDescriptor>() val declarationPatternsToTargets = MultiMap<DeclarationDescriptor, DeclarationDescriptor>()
val weakMatches = HashMap<JetElement, JetElement>()
var checkEquivalence: Boolean = false var checkEquivalence: Boolean = false
private fun matchDescriptors(d1: DeclarationDescriptor?, d2: DeclarationDescriptor?): Boolean { private fun matchDescriptors(d1: DeclarationDescriptor?, d2: DeclarationDescriptor?): Boolean {
@@ -720,6 +721,35 @@ public class JetPsiUnifier(
private fun ASTNode.getChildrenRange(): JetPsiRange = private fun ASTNode.getChildrenRange(): JetPsiRange =
getChildren(null).map { it.getPsi() }.filterNotNull().toRange() getChildren(null).map { it.getPsi() }.filterNotNull().toRange()
private fun PsiElement.unwrapWeakly(): JetElement? {
return when {
this is JetReturnExpression -> getReturnedExpression()
this is JetProperty -> getInitializer()
JetPsiUtil.isOrdinaryAssignment(this) -> (this as JetBinaryExpression).getRight()
this is JetExpression && this !is JetDeclaration -> this
else -> null
}
}
private fun doUnifyWeakly(
targetElement: JetElement,
patternElement: JetElement
): Status {
if (!allowWeakMatches) return UNMATCHED
val targetElementUnwrapped = targetElement.unwrapWeakly()
val patternElementUnwrapped = patternElement.unwrapWeakly()
if (targetElementUnwrapped == null || patternElementUnwrapped == null) return UNMATCHED
if (targetElementUnwrapped == targetElement && patternElementUnwrapped == patternElement) return UNMATCHED
val status = doUnify(targetElementUnwrapped, patternElementUnwrapped)
if (status == MATCHED && allowWeakMatches) {
weakMatches[patternElement] = targetElement
}
return status
}
fun doUnify( fun doUnify(
targetElement: PsiElement?, targetElement: PsiElement?,
patternElement: PsiElement? patternElement: PsiElement?
@@ -761,10 +791,17 @@ public class JetPsiUnifier(
if (targetNode == null || patternNode == null) return UNMATCHED if (targetNode == null || patternNode == null) return UNMATCHED
val resolvedStatus = matchResolvedInfo(targetElementUnwrapped, patternElementUnwrapped) val resolvedStatus = matchResolvedInfo(targetElementUnwrapped, patternElementUnwrapped)
if (resolvedStatus != null) return resolvedStatus if (resolvedStatus == MATCHED) return resolvedStatus
if (targetElementUnwrapped is JetElement && patternElementUnwrapped is JetElement) {
val weakStatus = doUnifyWeakly(targetElementUnwrapped, patternElementUnwrapped)
if (weakStatus != UNMATCHED) return weakStatus
}
if (targetNode.getElementType() != patternNode.getElementType()) return UNMATCHED if (targetNode.getElementType() != patternNode.getElementType()) return UNMATCHED
if (resolvedStatus != null) return resolvedStatus
val targetChildren = targetNode.getChildrenRange() val targetChildren = targetNode.getChildrenRange()
val patternChildren = patternNode.getChildrenRange() val patternChildren = patternNode.getChildrenRange()
@@ -798,7 +835,7 @@ public class JetPsiUnifier(
substitution.size != descriptorToParameter.size -> substitution.size != descriptorToParameter.size ->
Unmatched Unmatched
status == MATCHED -> status == MATCHED ->
Matched(substitution) if (weakMatches.isEmpty()) StronglyMatched(substitution) else WeaklyMatched(substitution, weakMatches)
else -> else ->
Unmatched Unmatched
} }