private boolean matchPattern(@Nullable PsiElement pattern,
                               @Nullable PsiElement candidate,
                               @NotNull List<PsiElement> candidates,
                               @NotNull Match match) {
    if (pattern == null || candidate == null) return pattern == candidate;
    final Boolean parameterMatches = matchParameter(pattern, candidate, match);
    if (parameterMatches != null) {
      return parameterMatches;
    }

    if (!canBeEquivalent(pattern, candidate)) {
      return false; // Q : is it correct to check implementation classes?
    }

    if (pattern instanceof PsiExpressionList && candidate instanceof PsiExpressionList) {
      Boolean matches = matchVarargs((PsiExpressionList)pattern, (PsiExpressionList)candidate, candidates, match);
      if (matches != null) {
        return matches;
      }
    }

    if (isParameterModification(pattern, candidate)) {
      return false;
    }

    if (pattern instanceof PsiJavaCodeReferenceElement && candidate instanceof PsiJavaCodeReferenceElement) {
      Boolean matches =
        matchReferenceElement((PsiJavaCodeReferenceElement)pattern, (PsiJavaCodeReferenceElement)candidate, candidates, match);
      if (matches != null) {
        return matches;
      }
    }

    if (pattern instanceof PsiTypeCastExpression && candidate instanceof PsiTypeCastExpression) {
      if (!isEquivalentTypeCast((PsiTypeCastExpression)pattern, (PsiTypeCastExpression)candidate)) {
        return false;
      }
    }
    else if (pattern instanceof PsiNewExpression && candidate instanceof PsiNewExpression) {
      if (!isEquivalentNewExpression((PsiNewExpression)pattern, (PsiNewExpression)candidate)) {
        return false;
      }
    }
    else if (pattern instanceof PsiClassObjectAccessExpression && candidate instanceof PsiClassObjectAccessExpression) {
      return matchObjectAccess((PsiClassObjectAccessExpression)pattern, (PsiClassObjectAccessExpression)candidate);
    }
    else if (pattern instanceof PsiInstanceOfExpression && candidate instanceof PsiInstanceOfExpression) {
      if (!isEquivalentInstanceOf((PsiInstanceOfExpression)pattern, (PsiInstanceOfExpression)candidate)) {
        return false;
      }
    } else if (pattern instanceof PsiReturnStatement) {
      return matchReturnStatement((PsiReturnStatement)pattern, candidate, candidates, match);
    } else if (pattern instanceof PsiContinueStatement) {
      match.registerReturnValue(new ContinueReturnValue());
    } else if (pattern instanceof PsiBreakStatement) {
      match.registerReturnValue(new BreakReturnValue());
    }
    else if (pattern instanceof PsiMethodCallExpression && candidate instanceof PsiMethodCallExpression) {
      if (!isEquivalentMethodCall((PsiMethodCallExpression)pattern, (PsiMethodCallExpression)candidate)) {
        return false;
      }
    }
    else if (pattern instanceof PsiReferenceExpression && candidate instanceof PsiReferenceExpression) {
      final Boolean matches = matchReferenceExpression((PsiReferenceExpression)pattern, (PsiReferenceExpression)candidate, match);
      if (matches != null) {
        return matches;
      }
    } else if (pattern instanceof PsiThisExpression) {
      return matchThisExpression((PsiThisExpression)pattern, candidate, match);
    }
    else if (pattern instanceof PsiSuperExpression && candidate instanceof PsiSuperExpression) {
      return matchSuperExpression((PsiSuperExpression)pattern, (PsiSuperExpression)candidate);
    }
    else if (pattern instanceof PsiModifierList && candidate instanceof PsiModifierList) {
      return matchModifierList((PsiModifierList)pattern, (PsiModifierList)candidate);
    }

    PsiElement[] children1 = getFilteredChildren(pattern);
    PsiElement[] children2 = getFilteredChildren(candidate);
    if (!matchChildren(children1, children2, candidates, match)) {
      return false;
    }

    if (children1.length == 0) {
      return matchLeaf(pattern, candidate, match);
    }

    return true;
  }
private boolean matchPattern(@Nullable PsiElement pattern,
                               @Nullable PsiElement candidate,
                               @NotNull List<PsiElement> candidates,
                               @NotNull Match match)