@Override
    public void visitReferenceExpression(@NotNull PsiReferenceExpression expression) {
      final PsiElement parent = PsiTreeUtil.skipParentsOfType(expression, PsiParenthesizedExpression.class);
      if (parent instanceof PsiSynchronizedStatement) {
        return;
      }
      final PsiElement referent = expression.resolve();
      if (!(referent instanceof PsiField) && !(referent instanceof PsiMethod)) {
        return;
      }
      final PsiMember member = (PsiMember)referent;
      final String guard = JCiPUtil.findGuardForMember(member);
      if (guard == null) {
        return;
      }
      final PsiExpression guardExpression;
      try {
        guardExpression = JavaPsiFacade.getElementFactory(expression.getProject()).createExpressionFromText(guard, member);
      } catch (IncorrectOperationException ignore) {
        return;
      }
      if (guardExpression instanceof PsiThisExpression && !PsiUtil.isAccessedForWriting(expression) &&
          member.hasModifierProperty(PsiModifier.VOLATILE)) {
        return;
      }
      final PsiMethod containingMethod = PsiTreeUtil.getParentOfType(expression, PsiMethod.class);
      if (containingMethod != null) {
        if (JCiPUtil.isGuardedBy(containingMethod, guard) || containingMethod.isConstructor()) {
          return;
        }
        if (containingMethod.hasModifierProperty(PsiModifier.SYNCHRONIZED)) {
          if (guardExpression instanceof PsiThisExpression thisExpression) {
            final PsiClass aClass = getClassFromThisExpression(thisExpression, member);
            if (aClass == null || InheritanceUtil.isInheritorOrSelf(containingMethod.getContainingClass(), aClass, true)) {
              return;
            }
          }
          else if (containingMethod.hasModifierProperty(PsiModifier.STATIC) && guardExpression instanceof PsiClassObjectAccessExpression) {
            PsiClass psiClass = PsiUtil.resolveClassInType(((PsiClassObjectAccessExpression)guardExpression).getOperand().getType());
            if (psiClass == null || psiClass.equals(containingMethod.getContainingClass())) {
              return;
            }
          }
        }
      }

      if (findLockTryStatement(expression, guard) != null) {
        PsiElement lockExpr = expression;
        while (lockExpr != null) {
          PsiElement child = lockExpr;
          while (child != null) {
            if (isLockGuardStatement(guard, child, "lock")) return;
            final PsiElement childParent = child.getParent();
            if (child instanceof PsiMethodCallExpression &&
                isCallOnGuard(guard, "tryLock", (PsiMethodCallExpression)child) &&
                childParent instanceof PsiIfStatement &&
                ((PsiIfStatement)childParent).getCondition() == child) {
              return;
            }
            child = child.getPrevSibling();
          }
          lockExpr = lockExpr.getParent();
        }
      }

      PsiElement check = expression;
      while (true) {
        final PsiSynchronizedStatement syncStatement = PsiTreeUtil.getParentOfType(check, PsiSynchronizedStatement.class);
        if (syncStatement == null) {
          break;
        }
        final PsiExpression lockExpression = PsiUtil.skipParenthesizedExprDown(syncStatement.getLockExpression());
        if (lockExpression == null) {
          continue;
        }
        if (guardExpression instanceof PsiThisExpression thisExpression1) {
          if (lockExpression instanceof PsiThisExpression thisExpression2) {
            final PsiClass aClass1 = getClassFromThisExpression(thisExpression1, member);
            final PsiClass aClass2 = getClassFromThisExpression(thisExpression2, expression);
            if (aClass1 == null || aClass1.equals(aClass2)) {
              return;
            }
          }
          else if (lockExpression instanceof PsiReferenceExpression) {
            final PsiExpression qualifierExpression = expression.getQualifierExpression();
            if (qualifierExpression != null && PsiEquivalenceUtil.areElementsEquivalent(lockExpression, qualifierExpression)) {
              return;
            }
          }
        }
        else if (guardExpression instanceof PsiReferenceExpression referenceExpression1 &&
                 lockExpression instanceof PsiReferenceExpression referenceExpression2) {
          final PsiElement target1 = referenceExpression1.resolve();
          final PsiElement target2 = referenceExpression2.resolve();
          if (target1 == null || target1.equals(target2)) {
            final PsiExpression lockQualifier = referenceExpression2.getQualifierExpression();
            if (referenceExpression1.getQualifierExpression() == null && lockQualifier != null) {
              final PsiExpression qualifierExpression = expression.getQualifierExpression();
              if (qualifierExpression != null && PsiEquivalenceUtil.areElementsEquivalent(lockQualifier, qualifierExpression)) {
                return;
              }
            } else {
              return;
            }
          }
        }
        else if (guardExpression instanceof PsiMethodCallExpression methodCallExpression1 &&
                 lockExpression instanceof PsiMethodCallExpression methodCallExpression2) {
          if (methodCallExpression2.getArgumentList().isEmpty()) {
            final PsiMethod method1 = methodCallExpression1.resolveMethod();
            final PsiMethod method2 = methodCallExpression2.resolveMethod();
            if (method1 == null || method1.equals(method2)) {
              final PsiReferenceExpression methodExpression2 = methodCallExpression2.getMethodExpression();
              final PsiExpression qualifierExpression1 = expression.getQualifierExpression();
              final PsiExpression qualifierExpression2 = methodExpression2.getQualifierExpression();
              if (qualifierExpression1 == null && qualifierExpression2 == null) {
                return;
              }
              if (qualifierExpression1 != null && qualifierExpression2 != null &&
                  PsiEquivalenceUtil.areElementsEquivalent(qualifierExpression1, qualifierExpression2)) {
                return;
              }
            }
          }
        }
        else if (guardExpression instanceof PsiClassObjectAccessExpression classObjectAccessExpression1 &&
                 lockExpression instanceof PsiClassObjectAccessExpression classObjectAccessExpression2) {
          final PsiClass aClass1 = PsiUtil.resolveClassInClassTypeOnly(classObjectAccessExpression1.getOperand().getType());
          final PsiClass aClass2 = PsiUtil.resolveClassInClassTypeOnly(classObjectAccessExpression2.getOperand().getType());
          if (aClass1 == null || aClass1.equals(aClass2)) {
            return;
          }
        }
        check = syncStatement;
      }
      myHolder.registerProblem(expression,
                               member instanceof PsiField ?
                               JavaAnalysisBundle.message("access.to.field.code.ref.code.outside.of.declared.guards.loc") :
                               JavaAnalysisBundle.message("call.to.method.code.ref.code.outside.of.declared.guards.loc"));
    }
@Override
    public void visitReferenceExpression(@NotNull PsiReferenceExpression expression)