@Override
  public void invoke(
      @NotNull final Project project, @NotNull Editor editor, @NotNull PsiFile file) {
    PsiDocumentManager.getInstance(project).commitAllDocuments();

    DumbService.getInstance(project).setAlternativeResolveEnabled(true);
    try {
      int offset = editor.getCaretModel().getOffset();
      PsiElement[] elements =
          underModalProgress(
              project,
              "Resolving Reference...",
              () -> findAllTargetElements(project, editor, offset));
      FeatureUsageTracker.getInstance().triggerFeatureUsed("navigation.goto.declaration");

      if (elements.length != 1) {
        if (elements.length == 0
            && suggestCandidates(TargetElementUtil.findReference(editor, offset)).isEmpty()) {
          PsiElement element =
              findElementToShowUsagesOf(editor, editor.getCaretModel().getOffset());
          if (startFindUsages(editor, element)) {
            return;
          }

          // disable 'no declaration found' notification for keywords
          final PsiElement elementAtCaret = file.findElementAt(offset);
          if (elementAtCaret != null) {
            final NamesValidator namesValidator =
                LanguageNamesValidation.INSTANCE.forLanguage(elementAtCaret.getLanguage());
            if (namesValidator != null
                && namesValidator.isKeyword(elementAtCaret.getText(), project)) {
              return;
            }
          }
        }
        chooseAmbiguousTarget(editor, offset, elements, file);
        return;
      }

      PsiElement element = elements[0];
      if (element == findElementToShowUsagesOf(editor, editor.getCaretModel().getOffset())
          && startFindUsages(editor, element)) {
        return;
      }

      PsiElement navElement = element.getNavigationElement();
      navElement = TargetElementUtil.getInstance().getGotoDeclarationTarget(element, navElement);
      if (navElement != null) {
        gotoTargetElement(navElement, editor, file);
      }
    } catch (IndexNotReadyException e) {
      DumbService.getInstance(project)
          .showDumbModeNotification("Navigation is not available here during index update");
    } finally {
      DumbService.getInstance(project).setAlternativeResolveEnabled(false);
    }
  }
  // returns true if processor is run or is going to be run after showing popup
  public static boolean chooseAmbiguousTarget(
      @NotNull Editor editor,
      int offset,
      @NotNull PsiElementProcessor<PsiElement> processor,
      @NotNull String titlePattern,
      @Nullable PsiElement[] elements) {
    if (TargetElementUtil.inVirtualSpace(editor, offset)) {
      return false;
    }

    final PsiReference reference = TargetElementUtil.findReference(editor, offset);

    if (elements == null || elements.length == 0) {
      elements =
          reference == null
              ? PsiElement.EMPTY_ARRAY
              : PsiUtilCore.toPsiElementArray(
                  underModalProgress(
                      reference.getElement().getProject(),
                      "Resolving Reference...",
                      () -> suggestCandidates(reference)));
    }

    if (elements.length == 1) {
      PsiElement element = elements[0];
      LOG.assertTrue(element != null);
      processor.execute(element);
      return true;
    }
    if (elements.length > 1) {
      String title;

      if (reference == null) {
        title = titlePattern;
      } else {
        final TextRange range = reference.getRangeInElement();
        final String elementText = reference.getElement().getText();
        LOG.assertTrue(
            range.getStartOffset() >= 0 && range.getEndOffset() <= elementText.length(),
            Arrays.toString(elements) + ";" + reference);
        final String refText = range.substring(elementText);
        title = MessageFormat.format(titlePattern, refText);
      }

      NavigationUtil.getPsiElementPopup(
              elements, new DefaultPsiElementCellRenderer(), title, processor)
          .showInBestPositionFor(editor);
      return true;
    }
    return false;
  }
  @Nullable
  public static PsiElement[] findTargetElementsNoVS(
      Project project, Editor editor, int offset, boolean lookupAccepted) {
    Document document = editor.getDocument();
    PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(document);
    if (file == null) return null;

    PsiElement elementAt =
        file.findElementAt(TargetElementUtil.adjustOffset(file, document, offset));
    for (GotoDeclarationHandler handler :
        Extensions.getExtensions(GotoDeclarationHandler.EP_NAME)) {
      try {
        PsiElement[] result = handler.getGotoDeclarationTargets(elementAt, offset, editor);
        if (result != null && result.length > 0) {
          for (PsiElement element : result) {
            if (element == null) {
              LOG.error("Null target element is returned by " + handler.getClass().getName());
              return null;
            }
          }
          return result;
        }
      } catch (AbstractMethodError e) {
        LOG.error(new ExtensionException(handler.getClass()));
      }
    }

    int flags =
        TargetElementUtil.getInstance().getAllAccepted() & ~TargetElementUtil.ELEMENT_NAME_ACCEPTED;
    if (!lookupAccepted) {
      flags &= ~TargetElementUtil.LOOKUP_ITEM_ACCEPTED;
    }
    PsiElement element = TargetElementUtil.getInstance().findTargetElement(editor, flags, offset);
    if (element != null) {
      return new PsiElement[] {element};
    }

    // if no references found in injected fragment, try outer document
    if (editor instanceof EditorWindow) {
      EditorWindow window = (EditorWindow) editor;
      return findTargetElementsNoVS(
          project,
          window.getDelegate(),
          window.getDocument().injectedToHost(offset),
          lookupAccepted);
    }

    return null;
  }
  public static void doTest(@NotNull final CodeInsightTestFixture fixture) {
    final List<CaretPositionInfo> caretPositions =
        DartTestUtils.extractPositionMarkers(
            fixture.getProject(), fixture.getEditor().getDocument());

    fixture.doHighlighting();

    for (CaretPositionInfo caretPositionInfo : caretPositions) {
      final int line =
          fixture.getEditor().getDocument().getLineNumber(caretPositionInfo.caretOffset);
      final int column =
          caretPositionInfo.caretOffset
              - fixture.getEditor().getDocument().getLineStartOffset(line);
      final String fileNameAndPosition =
          fixture.getFile().getName() + ":" + (line + 1) + ":" + (column + 1);

      final PsiReference reference =
          TargetElementUtil.findReference(fixture.getEditor(), caretPositionInfo.caretOffset);
      assertNotNull("No reference in " + fileNameAndPosition, reference);

      final PsiElement resolve = reference.resolve();
      final String actualElementPosition = getPresentableElementPosition(fixture, resolve);
      assertEquals(
          "Incorrect resolution for reference in " + fileNameAndPosition,
          caretPositionInfo.expected,
          actualElementPosition);
    }
  }
 public void invoke(
     @NotNull Project project, Editor editor, PsiFile file, DataContext dataContext) {
   editor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE);
   final int offset =
       TargetElementUtil.adjustOffset(
           file, editor.getDocument(), editor.getCaretModel().getOffset());
   final PsiElement element = file.findElementAt(offset);
   PsiTypeElement typeElement = PsiTreeUtil.getParentOfType(element, PsiTypeElement.class);
   while (typeElement != null) {
     final PsiElement parent = typeElement.getParent();
     PsiElement[] toMigrate = null;
     if (parent instanceof PsiVariable) {
       toMigrate = extractReferencedVariables(typeElement);
     } else if ((parent instanceof PsiMember && !(parent instanceof PsiClass))
         || isClassArgument(parent)) {
       toMigrate = new PsiElement[] {parent};
     }
     if (toMigrate != null && toMigrate.length > 0) {
       invoke(project, toMigrate, null, null, editor);
       return;
     }
     typeElement = PsiTreeUtil.getParentOfType(parent, PsiTypeElement.class, false);
   }
   CommonRefactoringUtil.showErrorHint(
       project,
       editor,
       "The caret should be positioned on type of field, variable, method or method parameter to be refactored",
       REFACTORING_NAME,
       "refactoring.migrateType");
 }
 @NotNull
 private static Collection<PsiElement> suggestCandidates(@Nullable PsiReference reference) {
   if (reference == null) {
     return Collections.emptyList();
   }
   return TargetElementUtil.getInstance().getTargetCandidates(reference);
 }
  private static boolean invoke(
      final PsiMethod method,
      final Project project,
      @Nullable final Editor editor,
      ChangeSignatureHandler initSubstisutor) {
    PsiMethod newMethod =
        SuperMethodWarningUtil.checkSuperMethod(method, RefactoringBundle.message("to.refactor"));
    if (newMethod == null) return false;

    if (!newMethod.equals(method)) {
      ChangeSignatureUtil.invokeChangeSignatureOn(newMethod, project);
      return true;
    }

    if (!CommonRefactoringUtil.checkReadOnlyStatus(project, method)) return false;

    final PsiClass containingClass = method.getContainingClass();
    final PsiReferenceExpression refExpr =
        editor != null ? TargetElementUtil.findReferenceExpression(editor) : null;
    final boolean allowDelegation = containingClass != null && !containingClass.isInterface();
    final DialogWrapper dialog =
        new GosuChangeSignatureDialog(
            project,
            new GosuMethodDescriptor((IGosuMethod) method, initSubstisutor),
            allowDelegation,
            refExpr,
            initSubstisutor);
    return dialog.showAndGet();
  }
 private boolean performRefactoring(@Nullable String expectedError) {
   try {
     final PsiElement element =
         TargetElementUtil.findTargetElement(
             myFixture.getEditor(), TargetElementUtil.getInstance().getReferenceSearchFlags());
     final PyInlineLocalHandler handler = PyInlineLocalHandler.getInstance();
     handler.inlineElement(myFixture.getProject(), myFixture.getEditor(), element);
     if (expectedError != null) fail("expected error: '" + expectedError + "', got none");
   } catch (Exception e) {
     if (!Comparing.equal(e.getMessage(), expectedError)) {
       e.printStackTrace();
     }
     assertEquals(expectedError, e.getMessage());
     return false;
   }
   return true;
 }
 @Override
 public void doApplyInformationToEditor() {
   final boolean virtSpace =
       TargetElementUtil.inVirtualSpace(myEditor, myEditor.getCaretModel().getOffset());
   final List<HighlightInfo> infos =
       virtSpace ? Collections.<HighlightInfo>emptyList() : getHighlights();
   UpdateHighlightersUtil.setHighlightersToEditor(
       myProject, myDocument, 0, myFile.getTextLength(), infos, getColorsScheme(), getId());
 }
  @NotNull
  @VisibleForTesting
  public static PsiElement[] findAllTargetElements(Project project, Editor editor, int offset) {
    if (TargetElementUtil.inVirtualSpace(editor, offset)) {
      return PsiElement.EMPTY_ARRAY;
    }

    final PsiElement[] targets = findTargetElementsNoVS(project, editor, offset, true);
    return targets != null ? targets : PsiElement.EMPTY_ARRAY;
  }
 public static PsiNameIdentifierOwner findElementToShowUsagesOf(
     @NotNull Editor editor, int offset) {
   PsiElement elementAt =
       TargetElementUtil.getInstance()
           .findTargetElement(editor, TargetElementUtil.ELEMENT_NAME_ACCEPTED, offset);
   if (elementAt instanceof PsiNameIdentifierOwner) {
     LOG.assertTrue(elementAt.isValid(), elementAt);
     return (PsiNameIdentifierOwner) elementAt;
   }
   return null;
 }
  public void testOnClickNavigation() throws Throwable {
    copyOnClickClasses();
    final VirtualFile file = copyFileToProject(getTestName(true) + ".xml");
    myFixture.configureFromExistingVirtualFile(file);

    final PsiReference reference =
        TargetElementUtil.findReference(myFixture.getEditor(), myFixture.getCaretOffset());
    assertNotNull(reference);
    assertInstanceOf(reference, PsiPolyVariantReference.class);
    final ResolveResult[] results = ((PsiPolyVariantReference) reference).multiResolve(false);
    assertEquals(2, results.length);
    for (ResolveResult result : results) {
      assertInstanceOf(result.getElement(), PsiMethod.class);
    }
  }
  private static void invoke(
      final PsiMethod method, final Project project, @Nullable final Editor editor) {
    if (!CommonRefactoringUtil.checkReadOnlyStatus(project, method)) return;

    PsiMethod newMethod =
        SuperMethodWarningUtil.checkSuperMethod(method, RefactoringBundle.message("to.refactor"));
    if (newMethod == null) return;

    if (!newMethod.equals(method)) {
      invoke(newMethod, project, editor);
      return;
    }

    if (!CommonRefactoringUtil.checkReadOnlyStatus(project, method)) return;

    final PsiClass containingClass = method.getContainingClass();
    final PsiReferenceExpression refExpr =
        editor != null ? TargetElementUtil.findReferenceExpression(editor) : null;
    final DialogWrapper dialog =
        new JavaChangeSignatureDialog(
            project, method, containingClass != null && !containingClass.isInterface(), refExpr);
    dialog.show();
  }
  @Override
  public void doCollectInformation(@NotNull final ProgressIndicator progress) {
    @SuppressWarnings("unchecked")
    HighlightUsagesHandlerBase<PsiElement> handler =
        HighlightUsagesHandler.createCustomHandler(myEditor, myFile);
    if (handler != null) {
      List<PsiElement> targets = handler.getTargets();
      handler.computeUsages(targets);
      final List<TextRange> readUsages = handler.getReadUsages();
      for (TextRange readUsage : readUsages) {
        LOG.assertTrue(readUsage != null, "null text range from " + handler);
      }
      myReadAccessRanges.addAll(readUsages);
      final List<TextRange> writeUsages = handler.getWriteUsages();
      for (TextRange writeUsage : writeUsages) {
        LOG.assertTrue(writeUsage != null, "null text range from " + handler);
      }
      myWriteAccessRanges.addAll(writeUsages);
      if (!handler.highlightReferences()) return;
    }

    int flags =
        TargetElementUtil.ELEMENT_NAME_ACCEPTED | TargetElementUtil.REFERENCED_ELEMENT_ACCEPTED;
    PsiElement myTarget;
    try {
      myTarget = TargetElementUtil.getInstance().findTargetElement(myEditor, flags, myCaretOffset);
    } catch (IndexNotReadyException e) {
      return;
    }

    if (myTarget == null) {
      if (!PsiDocumentManager.getInstance(myProject).isUncommited(myEditor.getDocument())) {
        // when document is committed, try to check injected stuff - it's fast
        Editor injectedEditor =
            InjectedLanguageUtil.getEditorForInjectedLanguageNoCommit(
                myEditor, myFile, myCaretOffset);
        myTarget =
            TargetElementUtil.getInstance()
                .findTargetElement(
                    injectedEditor, flags, injectedEditor.getCaretModel().getOffset());
      }
    }

    if (myTarget != null) {
      highlightTargetUsages(myTarget);
    } else {
      PsiReference ref = TargetElementUtil.findReference(myEditor);
      if (ref instanceof PsiPolyVariantReference) {
        if (!ref.getElement().isValid()) {
          throw new PsiInvalidElementAccessException(
              ref.getElement(),
              "Invalid element in " + ref + " of " + ref.getClass() + "; editor=" + myEditor);
        }
        ResolveResult[] results = ((PsiPolyVariantReference) ref).multiResolve(false);
        if (results.length > 0) {
          for (ResolveResult result : results) {
            PsiElement target = result.getElement();
            if (target != null) {
              if (!target.isValid()) {
                throw new PsiInvalidElementAccessException(
                    target,
                    "Invalid element returned from "
                        + ref
                        + " of "
                        + ref.getClass()
                        + "; editor="
                        + myEditor);
              }
              highlightTargetUsages(target);
            }
          }
        }
      }
    }
  }
  public void inlineElement(
      final Project project, final Editor editor, final PsiElement psiElement) {
    final PsiParameter psiParameter = (PsiParameter) psiElement;
    final PsiParameterList parameterList = (PsiParameterList) psiParameter.getParent();
    if (!(parameterList.getParent() instanceof PsiMethod)) {
      return;
    }
    final int index = parameterList.getParameterIndex(psiParameter);
    final PsiMethod method = (PsiMethod) parameterList.getParent();

    String errorMessage = getCannotInlineMessage(psiParameter, method);
    if (errorMessage != null) {
      CommonRefactoringUtil.showErrorHint(
          project,
          editor,
          errorMessage,
          RefactoringBundle.message("inline.parameter.refactoring"),
          null);
      return;
    }

    final Ref<PsiExpression> refInitializer = new Ref<PsiExpression>();
    final Ref<PsiExpression> refConstantInitializer = new Ref<PsiExpression>();
    final Ref<PsiCallExpression> refMethodCall = new Ref<PsiCallExpression>();
    final List<PsiReference> occurrences =
        Collections.synchronizedList(new ArrayList<PsiReference>());
    final Collection<PsiFile> containingFiles = Collections.synchronizedSet(new HashSet<PsiFile>());
    containingFiles.add(psiParameter.getContainingFile());
    boolean result =
        ReferencesSearch.search(method)
            .forEach(
                new Processor<PsiReference>() {
                  public boolean process(final PsiReference psiReference) {
                    PsiElement element = psiReference.getElement();
                    final PsiElement parent = element.getParent();
                    if (parent instanceof PsiCallExpression) {
                      final PsiCallExpression methodCall = (PsiCallExpression) parent;
                      occurrences.add(psiReference);
                      containingFiles.add(element.getContainingFile());
                      final PsiExpression[] expressions =
                          methodCall.getArgumentList().getExpressions();
                      if (expressions.length <= index) return false;
                      PsiExpression argument = expressions[index];
                      if (!refInitializer.isNull()) {
                        return argument != null
                            && PsiEquivalenceUtil.areElementsEquivalent(
                                refInitializer.get(), argument)
                            && PsiEquivalenceUtil.areElementsEquivalent(
                                refMethodCall.get(), methodCall);
                      }
                      if (InlineToAnonymousConstructorProcessor.isConstant(argument)
                          || getReferencedFinalField(argument) != null) {
                        if (refConstantInitializer.isNull()) {
                          refConstantInitializer.set(argument);
                        } else if (!isSameConstant(argument, refConstantInitializer.get())) {
                          return false;
                        }
                      } else if (!isRecursiveReferencedParameter(argument, psiParameter)) {
                        if (!refConstantInitializer.isNull()) return false;
                        refInitializer.set(argument);
                        refMethodCall.set(methodCall);
                      }
                    }
                    return true;
                  }
                });
    final PsiReference reference = TargetElementUtil.findReference(editor);
    final PsiReferenceExpression refExpr =
        reference instanceof PsiReferenceExpression ? ((PsiReferenceExpression) reference) : null;
    final PsiCodeBlock codeBlock = PsiTreeUtil.getParentOfType(refExpr, PsiCodeBlock.class);
    if (codeBlock != null) {
      final PsiElement[] defs = DefUseUtil.getDefs(codeBlock, psiParameter, refExpr);
      if (defs.length == 1) {
        final PsiElement def = defs[0];
        if (def instanceof PsiReferenceExpression
            && PsiUtil.isOnAssignmentLeftHand((PsiExpression) def)) {
          final PsiExpression rExpr = ((PsiAssignmentExpression) def.getParent()).getRExpression();
          if (rExpr != null) {
            PsiExpression toInline =
                InlineLocalHandler.getDefToInline(psiParameter, refExpr, codeBlock);
            if (toInline != null) {
              final PsiElement[] refs = DefUseUtil.getRefs(codeBlock, psiParameter, toInline);

              if (InlineLocalHandler.checkRefsInAugmentedAssignmentOrUnaryModified(refs, def)
                  == null) {
                new WriteCommandAction(project) {
                  @Override
                  protected void run(Result result) throws Throwable {
                    for (final PsiElement ref : refs) {
                      InlineUtil.inlineVariable(
                          psiParameter, rExpr, (PsiJavaCodeReferenceElement) ref);
                    }
                    def.getParent().delete();
                  }
                }.execute();
                return;
              }
            }
          }
        }
      }
    }
    if (occurrences.isEmpty()) {
      CommonRefactoringUtil.showErrorHint(
          project,
          editor,
          "Method has no usages",
          RefactoringBundle.message("inline.parameter.refactoring"),
          null);
      return;
    }
    if (!result) {
      CommonRefactoringUtil.showErrorHint(
          project,
          editor,
          "Cannot find constant initializer for parameter",
          RefactoringBundle.message("inline.parameter.refactoring"),
          null);
      return;
    }
    if (!refInitializer.isNull()) {
      if (ApplicationManager.getApplication().isUnitTestMode()) {
        final InlineParameterExpressionProcessor processor =
            new InlineParameterExpressionProcessor(
                refMethodCall.get(),
                method,
                psiParameter,
                refInitializer.get(),
                method
                    .getProject()
                    .getUserData(InlineParameterExpressionProcessor.CREATE_LOCAL_FOR_TESTS));
        processor.run();
      } else {
        final boolean createLocal = ReferencesSearch.search(psiParameter).findAll().size() > 1;
        InlineParameterDialog dlg =
            new InlineParameterDialog(
                refMethodCall.get(), method, psiParameter, refInitializer.get(), createLocal);
        dlg.show();
      }
      return;
    }
    if (refConstantInitializer.isNull()) {
      CommonRefactoringUtil.showErrorHint(
          project,
          editor,
          "Cannot find constant initializer for parameter",
          RefactoringBundle.message("inline.parameter.refactoring"),
          null);
      return;
    }

    final Ref<Boolean> isNotConstantAccessible = new Ref<Boolean>();
    final PsiExpression constantExpression = refConstantInitializer.get();
    constantExpression.accept(
        new JavaRecursiveElementVisitor() {
          @Override
          public void visitReferenceExpression(PsiReferenceExpression expression) {
            super.visitReferenceExpression(expression);
            final PsiElement resolved = expression.resolve();
            if (resolved instanceof PsiMember
                && !PsiUtil.isAccessible((PsiMember) resolved, method, null)) {
              isNotConstantAccessible.set(Boolean.TRUE);
            }
          }
        });
    if (!isNotConstantAccessible.isNull() && isNotConstantAccessible.get()) {
      CommonRefactoringUtil.showErrorHint(
          project,
          editor,
          "Constant initializer is not accessible in method body",
          RefactoringBundle.message("inline.parameter.refactoring"),
          null);
      return;
    }

    for (PsiReference psiReference : ReferencesSearch.search(psiParameter)) {
      final PsiElement element = psiReference.getElement();
      if (element instanceof PsiExpression
          && PsiUtil.isAccessedForWriting((PsiExpression) element)) {
        CommonRefactoringUtil.showErrorHint(
            project,
            editor,
            "Inline parameter which has write usages is not supported",
            RefactoringBundle.message("inline.parameter.refactoring"),
            null);
        return;
      }
    }

    if (!ApplicationManager.getApplication().isUnitTestMode()) {
      String occurencesString = RefactoringBundle.message("occurrences.string", occurrences.size());
      String question =
          RefactoringBundle.message(
                  "inline.parameter.confirmation",
                  psiParameter.getName(),
                  constantExpression.getText())
              + " "
              + occurencesString;
      RefactoringMessageDialog dialog =
          new RefactoringMessageDialog(
              REFACTORING_NAME,
              question,
              HelpID.INLINE_VARIABLE,
              "OptionPane.questionIcon",
              true,
              project);
      if (!dialog.showAndGet()) {
        return;
      }
    }

    final RefactoringEventData data = new RefactoringEventData();
    data.addElement(psiElement.copy());

    CommandProcessor.getInstance()
        .executeCommand(
            project,
            new Runnable() {
              @Override
              public void run() {
                project
                    .getMessageBus()
                    .syncPublisher(RefactoringEventListener.REFACTORING_EVENT_TOPIC)
                    .refactoringStarted(REFACTORING_ID, data);
                SameParameterValueInspection.InlineParameterValueFix.inlineSameParameterValue(
                    method, psiParameter, constantExpression);
                project
                    .getMessageBus()
                    .syncPublisher(RefactoringEventListener.REFACTORING_EVENT_TOPIC)
                    .refactoringDone(REFACTORING_ID, null);
              }
            },
            REFACTORING_NAME,
            null);
  }