@Override
 public void visitReferenceExpression(@NotNull PsiReferenceExpression reference) {
   if (used) {
     return;
   }
   super.visitReferenceExpression(reference);
   final PsiElement element = reference.resolve();
   if (parameter.equals(element)) {
     used = true;
   }
 }
 @Override
 public void visitReferenceExpression(PsiReferenceExpression expression) {
   if (argumentsContainCatchParameter || !visited.add(expression)) {
     return;
   }
   super.visitReferenceExpression(expression);
   final PsiElement target = expression.resolve();
   if (!parameter.equals(target)) {
     if (target instanceof PsiLocalVariable) {
       final PsiLocalVariable variable = (PsiLocalVariable) target;
       final Query<PsiReference> query =
           ReferencesSearch.search(variable, variable.getUseScope(), false);
       query.forEach(
           reference -> {
             final PsiElement element = reference.getElement();
             final PsiElement parent =
                 PsiTreeUtil.skipParentsOfType(element, PsiParenthesizedExpression.class);
             if (!(parent instanceof PsiReferenceExpression)) {
               return true;
             }
             final PsiElement grandParent = parent.getParent();
             if (!(grandParent instanceof PsiMethodCallExpression)) {
               return true;
             }
             final PsiMethodCallExpression methodCallExpression =
                 (PsiMethodCallExpression) grandParent;
             final PsiExpressionList argumentList = methodCallExpression.getArgumentList();
             final PsiExpression[] arguments = argumentList.getExpressions();
             for (PsiExpression argument : arguments) {
               argument.accept(ReferenceFinder.this);
             }
             return true;
           });
       final PsiExpression initializer = variable.getInitializer();
       if (initializer != null) {
         initializer.accept(this);
       }
     }
     return;
   }
   if (ignoreGetMessage) {
     argumentsContainCatchParameter = true;
   } else {
     final PsiElement parent = expression.getParent();
     if (parent instanceof PsiReferenceExpression) {
       final PsiElement grandParent = parent.getParent();
       if (grandParent instanceof PsiMethodCallExpression) {
         return;
       }
     }
     argumentsContainCatchParameter = true;
   }
 }
 public static int getParameterIndex(
     @NotNull PsiParameter parameter, @NotNull PsiParameterList parameterList) {
   PsiParameter[] parameters = parameterList.getParameters();
   for (int i = 0; i < parameters.length; i++) {
     PsiParameter paramInList = parameters[i];
     if (parameter.equals(paramInList)) return i;
   }
   String name = parameter.getName();
   PsiParameter suspect = null;
   int i;
   for (i = parameters.length - 1; i >= 0; i--) {
     PsiParameter paramInList = parameters[i];
     if (name.equals(paramInList.getName())) {
       suspect = paramInList;
       break;
     }
   }
   String message =
       parameter
           + ":"
           + parameter.getClass()
           + " not found among parameters: "
           + Arrays.asList(parameters)
           + "."
           + " parameterList' parent: "
           + parameterList.getParent()
           + ";"
           + " parameter.getParent()==paramList: "
           + (parameter.getParent() == parameterList)
           + "; "
           + parameterList.getClass()
           + ";"
           + " parameter.isValid()="
           + parameter.isValid()
           + ";"
           + " parameterList.isValid()= "
           + parameterList.isValid()
           + ";"
           + " parameterList stub: "
           + (parameterList instanceof StubBasedPsiElement
               ? ((StubBasedPsiElement) parameterList).getStub()
               : "---")
           + "; "
           + " parameter stub: "
           + (parameter instanceof StubBasedPsiElement
               ? ((StubBasedPsiElement) parameter).getStub()
               : "---")
           + ";"
           + " suspect: "
           + suspect
           + " (index="
           + i
           + "); "
           + (suspect == null ? null : suspect.getClass())
           + " suspect stub: "
           + (suspect instanceof StubBasedPsiElement
               ? ((StubBasedPsiElement) suspect).getStub()
               : suspect == null ? "-null-" : "---" + suspect.getClass())
           + ";"
           + " parameter.equals(suspect) = "
           + parameter.equals(suspect)
           + "; "
           + " parameter.getNode() == suspect.getNode():  "
           + (parameter.getNode() == (suspect == null ? null : suspect.getNode()))
           + "; "
           + ".";
   LOG.error(message);
   return i;
 }
  private void addTypesByVariable(
      HashSet<PsiType> typesSet,
      PsiVariable var,
      PsiFile scopeFile,
      HashSet<PsiVariable> checkedVariables,
      int flags,
      TextRange rangeToIgnore) {
    if (!checkedVariables.add(var)) return;
    // System.out.println("analyzing usages of " + var + " in file " + scopeFile);
    SearchScope searchScope = new LocalSearchScope(scopeFile);

    if (BitUtil.isSet(flags, CHECK_USAGE) || BitUtil.isSet(flags, CHECK_DOWN)) {
      for (PsiReference varRef : ReferencesSearch.search(var, searchScope, false)) {
        PsiElement ref = varRef.getElement();

        if (BitUtil.isSet(flags, CHECK_USAGE)) {
          PsiType type = guessElementTypeFromReference(myMethodPatternMap, ref, rangeToIgnore);
          if (type != null && !(type instanceof PsiPrimitiveType)) {
            typesSet.add(type);
          }
        }

        if (BitUtil.isSet(flags, CHECK_DOWN)) {
          if (ref.getParent() instanceof PsiExpressionList
              && ref.getParent().getParent() instanceof PsiMethodCallExpression) { // TODO : new
            PsiExpressionList list = (PsiExpressionList) ref.getParent();
            PsiExpression[] args = list.getExpressions();
            int argIndex = -1;
            for (int j = 0; j < args.length; j++) {
              PsiExpression arg = args[j];
              if (arg.equals(ref)) {
                argIndex = j;
                break;
              }
            }

            PsiMethodCallExpression methodCall = (PsiMethodCallExpression) list.getParent();
            PsiMethod method = (PsiMethod) methodCall.getMethodExpression().resolve();
            if (method != null) {
              PsiParameter[] parameters = method.getParameterList().getParameters();
              if (argIndex < parameters.length) {
                addTypesByVariable(
                    typesSet,
                    parameters[argIndex],
                    method.getContainingFile(),
                    checkedVariables,
                    flags | CHECK_USAGE,
                    rangeToIgnore);
              }
            }
          }
        }
      }
    }

    if (BitUtil.isSet(flags, CHECK_UP)) {
      if (var instanceof PsiParameter
          && var.getParent() instanceof PsiParameterList
          && var.getParent().getParent() instanceof PsiMethod) {
        PsiParameterList list = (PsiParameterList) var.getParent();
        PsiParameter[] parameters = list.getParameters();
        int argIndex = -1;
        for (int i = 0; i < parameters.length; i++) {
          PsiParameter parameter = parameters[i];
          if (parameter.equals(var)) {
            argIndex = i;
            break;
          }
        }

        PsiMethod method = (PsiMethod) var.getParent().getParent();
        // System.out.println("analyzing usages of " + method + " in file " + scopeFile);
        for (PsiReference methodRef : ReferencesSearch.search(method, searchScope, false)) {
          PsiElement ref = methodRef.getElement();
          if (ref.getParent() instanceof PsiMethodCallExpression) {
            PsiMethodCallExpression methodCall = (PsiMethodCallExpression) ref.getParent();
            PsiExpression[] args = methodCall.getArgumentList().getExpressions();
            if (args.length <= argIndex) continue;
            PsiExpression arg = args[argIndex];
            if (arg instanceof PsiReferenceExpression) {
              PsiElement refElement = ((PsiReferenceExpression) arg).resolve();
              if (refElement instanceof PsiVariable) {
                addTypesByVariable(
                    typesSet,
                    (PsiVariable) refElement,
                    scopeFile,
                    checkedVariables,
                    flags | CHECK_USAGE,
                    rangeToIgnore);
              }
            }
            // TODO : constructor
          }
        }
      }
    }
  }