@Override
  public void visitReferenceExpression(@NotNull PsiReferenceExpression reference) {
    final MatchContext context = myMatchingVisitor.getMatchContext();
    final CompiledPattern pattern = context.getPattern();
    final PsiElement referenceNameElement = reference.getReferenceNameElement();
    assert referenceNameElement != null;
    MatchingHandler _handler = pattern.getHandlerSimple(referenceNameElement);
    boolean special = false;
    if (_handler == null) {
      _handler = pattern.getHandlerSimple(reference);
      special = reference.resolve() != null;
    }

    final PsiElement other = myMatchingVisitor.getElement();
    final PsiElement unwrapped = unwrap(other, context);
    final PsiExpression qualifier = reference.getQualifierExpression();
    if (_handler instanceof SubstitutionHandler handler && (qualifier == null || special)) {
      if (other instanceof PsiReferenceExpression && other.getParent() instanceof PsiMethodCallExpression) {
        myMatchingVisitor.setResult(false);
        return;
      }
      if (handler.isSubtype() || handler.isStrictSubtype()) {
        if (myMatchingVisitor.setResult(matchWithinHierarchy(reference, unwrapped, handler))) {
          handler.addResult(other, myMatchingVisitor.getMatchContext());
        }
      }
      else if (myMatchingVisitor.setResult(handler.validate(unwrapped, context))) {
        handler.addResult(other, context);
      }
      return;
    }

    final boolean multiMatch = unwrapped != null && reference.getContainingFile() == unwrapped.getContainingFile();
    if (!(unwrapped instanceof PsiReferenceExpression reference2)) {
      // when the same variable is used multiple times in a pattern, we need to check if they are the same,
      // but sometimes they are not normally comparable. In this case we fall back to a text comparison.
      // For example in the pattern `boolean equals(Object $x$) { return super.equals($x$); }`
      // the PsiReferenceExpression argument will be compared to the PsiIdentifier of the parameter.
      myMatchingVisitor.setResult(multiMatch && myMatchingVisitor.matchText(reference, unwrapped));
      return;
    }

    final PsiExpression qualifier2 = reference2.getQualifierExpression();
    if (multiMatch &&
        (qualifier == null || qualifier instanceof PsiThisExpression || qualifier instanceof PsiSuperExpression) &&
        (qualifier2 == null || qualifier2 instanceof PsiThisExpression || qualifier2 instanceof PsiSuperExpression)) {
      final PsiElement target = reference.resolve();
      if (target != null) {
        myMatchingVisitor.setResult(target == reference2.resolve());
        return;
      }
    }
    if (qualifier == null && qualifier2 == null) {
      myMatchingVisitor.setResult(myMatchingVisitor.matchText(referenceNameElement, reference2.getReferenceNameElement()));
      return;
    }

    // handle field selection
    if (myMatchingVisitor.setResult(!(other.getParent() instanceof PsiMethodCallExpression) && qualifier != null)) {
      final PsiElement referenceNameElement2 = reference2.getReferenceNameElement();

      if (pattern.isTypedVar(referenceNameElement)) {
        if (!myMatchingVisitor.setResult(myMatchingVisitor.handleTypedElement(referenceNameElement, referenceNameElement2))) return;
      }
      else {
        if (!myMatchingVisitor.setResult(myMatchingVisitor.matchText(referenceNameElement, referenceNameElement2))) return;
      }

      if (!myMatchingVisitor.setResult(qualifier instanceof PsiThisExpression && qualifier2 == null ||
                                       myMatchingVisitor.matchOptionally(qualifier, qualifier2))) return;
      if (qualifier2 == null) myMatchingVisitor.setResult(matchImplicitQualifier(qualifier, unwrapped, context));
    }
  }
@Override
  public void visitReferenceExpression(@NotNull PsiReferenceExpression reference)