private static void addFieldsUsages(
     final PsiClass aClass,
     final Processor<UsageInfo> results,
     final JavaClassFindUsagesOptions options) {
   if (options.isIncludeInherited) {
     final PsiManager manager = aClass.getManager();
     PsiField[] fields = aClass.getAllFields();
     FieldsLoop:
     for (int i = 0; i < fields.length; i++) {
       final PsiField field = fields[i];
       // filter hidden fields
       for (int j = 0; j < i; j++) {
         if (Comparing.strEqual(field.getName(), fields[j].getName())) continue FieldsLoop;
       }
       final PsiClass fieldClass = field.getContainingClass();
       if (manager.areElementsEquivalent(fieldClass, aClass)) {
         addElementUsages(fields[i], results, options);
       } else {
         ReferencesSearch.search(
                 new ReferencesSearch.SearchParameters(
                     field, options.searchScope, false, options.fastTrack))
             .forEach(
                 new ReadActionProcessor<PsiReference>() {
                   @Override
                   public boolean processInReadAction(final PsiReference reference) {
                     addResultFromReference(
                         reference, fieldClass, manager, aClass, results, options);
                     return true;
                   }
                 });
       }
     }
   } else {
     PsiField[] fields =
         ApplicationManager.getApplication()
             .runReadAction(
                 new Computable<PsiField[]>() {
                   @Override
                   public PsiField[] compute() {
                     return aClass.getFields();
                   }
                 });
     for (PsiField field : fields) {
       addElementUsages(field, results, options);
     }
   }
 }
 private static void addResultFromReference(
     final PsiReference reference,
     final PsiClass methodClass,
     final PsiManager manager,
     final PsiClass aClass,
     final Processor<UsageInfo> results,
     final FindUsagesOptions options) {
   PsiElement refElement = reference.getElement();
   if (refElement instanceof PsiReferenceExpression) {
     PsiClass usedClass =
         getFieldOrMethodAccessedClass((PsiReferenceExpression) refElement, methodClass);
     if (usedClass != null) {
       if (manager.areElementsEquivalent(usedClass, aClass)
           || usedClass.isInheritor(aClass, true)) {
         addResult(results, refElement, options);
       }
     }
   }
 }
 private static void addMethodsUsages(
     final PsiClass aClass,
     final Processor<UsageInfo> results,
     final JavaClassFindUsagesOptions options) {
   if (options.isIncludeInherited) {
     final PsiManager manager = aClass.getManager();
     PsiMethod[] methods = aClass.getAllMethods();
     MethodsLoop:
     for (int i = 0; i < methods.length; i++) {
       final PsiMethod method = methods[i];
       // filter overriden methods
       MethodSignature methodSignature = method.getSignature(PsiSubstitutor.EMPTY);
       for (int j = 0; j < i; j++) {
         if (methodSignature.equals(methods[j].getSignature(PsiSubstitutor.EMPTY)))
           continue MethodsLoop;
       }
       final PsiClass methodClass = method.getContainingClass();
       if (methodClass != null && manager.areElementsEquivalent(methodClass, aClass)) {
         addElementUsages(methods[i], results, options);
       } else {
         MethodReferencesSearch.search(
                 new MethodReferencesSearch.SearchParameters(
                     method, options.searchScope, true, options.fastTrack))
             .forEach(
                 new PsiReferenceProcessorAdapter(
                     new PsiReferenceProcessor() {
                       @Override
                       public boolean execute(PsiReference reference) {
                         addResultFromReference(
                             reference, methodClass, manager, aClass, results, options);
                         return true;
                       }
                     }));
       }
     }
   } else {
     for (PsiMethod method : aClass.getMethods()) {
       addElementUsages(method, results, options);
     }
   }
 }
  @Override
  public void processElementUsages(
      @NotNull final PsiElement element,
      @NotNull final Processor<UsageInfo> processor,
      @NotNull final FindUsagesOptions options) {
    if (options instanceof JavaVariableFindUsagesOptions) {
      final JavaVariableFindUsagesOptions varOptions = (JavaVariableFindUsagesOptions) options;
      if (varOptions.isReadAccess || varOptions.isWriteAccess) {
        if (varOptions.isReadAccess && varOptions.isWriteAccess) {
          addElementUsages(element, processor, options);
        } else {
          addElementUsages(
              element,
              new Processor<UsageInfo>() {
                @Override
                public boolean process(UsageInfo info) {
                  final PsiElement element = info.getElement();
                  boolean isWrite =
                      element instanceof PsiExpression
                          && PsiUtil.isAccessedForWriting((PsiExpression) element);
                  if (isWrite == varOptions.isWriteAccess) {
                    if (!processor.process(info)) return false;
                  }
                  return true;
                }
              },
              varOptions);
        }
      }
    } else if (options.isUsages) {
      addElementUsages(element, processor, options);
    }

    ApplicationManager.getApplication()
        .runReadAction(
            new Runnable() {
              @Override
              public void run() {
                if (ThrowSearchUtil.isSearchable(element)
                    && options instanceof JavaThrowFindUsagesOptions
                    && options.isUsages) {
                  ThrowSearchUtil.Root root =
                      options.getUserData(ThrowSearchUtil.THROW_SEARCH_ROOT_KEY);
                  if (root == null) {
                    final ThrowSearchUtil.Root[] roots = ThrowSearchUtil.getSearchRoots(element);
                    if (roots != null && roots.length > 0) {
                      root = roots[0];
                    }
                  }
                  if (root != null) {
                    ThrowSearchUtil.addThrowUsages(processor, root, options);
                  }
                }
              }
            });

    if (options instanceof JavaPackageFindUsagesOptions
        && ((JavaPackageFindUsagesOptions) options).isClassesUsages) {
      addClassesUsages((PsiPackage) element, processor, (JavaPackageFindUsagesOptions) options);
    }

    if (options instanceof JavaClassFindUsagesOptions) {
      final JavaClassFindUsagesOptions classOptions = (JavaClassFindUsagesOptions) options;
      final PsiClass psiClass = (PsiClass) element;
      if (classOptions.isMethodsUsages) {
        addMethodsUsages(psiClass, processor, classOptions);
      }
      if (classOptions.isFieldsUsages) {
        addFieldsUsages(psiClass, processor, classOptions);
      }
      if (psiClass.isInterface()) {
        if (classOptions.isDerivedInterfaces) {
          if (classOptions.isImplementingClasses) {
            addInheritors(psiClass, processor, classOptions);
          } else {
            addDerivedInterfaces(psiClass, processor, classOptions);
          }
        } else if (classOptions.isImplementingClasses) {
          addImplementingClasses(psiClass, processor, classOptions);
        }
      } else if (classOptions.isDerivedClasses) {
        addInheritors(psiClass, processor, classOptions);
      }
    }

    if (options instanceof JavaMethodFindUsagesOptions) {
      final PsiMethod psiMethod = (PsiMethod) element;
      boolean isAbstract =
          ApplicationManager.getApplication()
              .runReadAction(
                  new Computable<Boolean>() {
                    @Override
                    public Boolean compute() {
                      return psiMethod.hasModifierProperty(PsiModifier.ABSTRACT);
                    }
                  });
      final JavaMethodFindUsagesOptions methodOptions = (JavaMethodFindUsagesOptions) options;
      if (isAbstract && methodOptions.isImplementingMethods || methodOptions.isOverridingMethods) {
        processOverridingMethods(psiMethod, processor, methodOptions);
      }
    }

    if (element instanceof PomTarget) {
      addAliasingUsages((PomTarget) element, processor, options);
    }
    final Boolean isSearchable =
        ApplicationManager.getApplication()
            .runReadAction(
                new Computable<Boolean>() {
                  @Override
                  public Boolean compute() {
                    return ThrowSearchUtil.isSearchable(element);
                  }
                });
    if (!isSearchable
        && options.isSearchForTextOccurrences
        && options.searchScope instanceof GlobalSearchScope) {
      // todo add to fastTrack
      processUsagesInText(element, processor, (GlobalSearchScope) options.searchScope);
    }
  }
 @Override
 @NotNull
 public PsiElement[] getSecondaryElements() {
   PsiElement element = getPsiElement();
   if (ApplicationManager.getApplication().isUnitTestMode()) return PsiElement.EMPTY_ARRAY;
   if (element instanceof PsiField) {
     final PsiField field = (PsiField) element;
     PsiClass containingClass = field.getContainingClass();
     if (containingClass != null) {
       String fieldName = field.getName();
       final String propertyName =
           JavaCodeStyleManager.getInstance(getProject())
               .variableNameToPropertyName(fieldName, VariableKind.FIELD);
       Set<PsiMethod> accessors = new THashSet<PsiMethod>();
       boolean isStatic = field.hasModifierProperty(PsiModifier.STATIC);
       PsiMethod getter =
           PropertyUtil.findPropertyGetterWithType(
               propertyName,
               isStatic,
               field.getType(),
               ContainerUtil.iterate(containingClass.getMethods()));
       if (getter != null) accessors.add(getter);
       PsiMethod setter =
           PropertyUtil.findPropertySetterWithType(
               propertyName,
               isStatic,
               field.getType(),
               ContainerUtil.iterate(containingClass.getMethods()));
       if (setter != null) accessors.add(setter);
       accessors.addAll(PropertyUtil.getAccessors(containingClass, fieldName));
       if (!accessors.isEmpty()) {
         final boolean doSearch;
         boolean containsPhysical =
             ContainerUtil.find(
                     accessors,
                     new Condition<PsiMethod>() {
                       @Override
                       public boolean value(PsiMethod psiMethod) {
                         return psiMethod.isPhysical();
                       }
                     })
                 != null;
         if (!containsPhysical) {
           doSearch = true;
         } else {
           doSearch =
               Messages.showOkCancelDialog(
                       FindBundle.message("find.field.accessors.prompt", fieldName),
                       FindBundle.message("find.field.accessors.title"),
                       CommonBundle.getYesButtonText(),
                       CommonBundle.getNoButtonText(),
                       Messages.getQuestionIcon())
                   == DialogWrapper.OK_EXIT_CODE;
         }
         if (doSearch) {
           final Set<PsiElement> elements = new THashSet<PsiElement>();
           for (PsiMethod accessor : accessors) {
             ContainerUtil.addAll(
                 elements, SuperMethodWarningUtil.checkSuperMethods(accessor, ACTION_STRING));
           }
           return PsiUtilBase.toPsiElementArray(elements);
         }
       }
     }
   }
   return super.getSecondaryElements();
 }