@Override
 protected void collectNavigationMarkers(
     @NotNull PsiElement element, Collection<? super RelatedItemLineMarkerInfo> result) {
   final PsiElement pythonStub = getPythonStub(element);
   if (pythonStub != null) {
     final List<GotoRelatedItem> relatedItems =
         GotoRelatedItem.createItems(Collections.singletonList(pythonStub));
     result.add(
         new RelatedItemLineMarkerInfo<PsiElement>(
             element,
             element.getTextRange(),
             ICON,
             Pass.LINE_MARKERS,
             element1 -> "Has stub item in " + pythonStub.getContainingFile().getName(),
             new GutterIconNavigationHandler<PsiElement>() {
               @Override
               public void navigate(MouseEvent e, PsiElement elt) {
                 final PsiElement pythonStub = getPythonStub(elt);
                 if (pythonStub != null) {
                   PsiNavigateUtil.navigate(pythonStub);
                 }
               }
             },
             GutterIconRenderer.Alignment.RIGHT,
             relatedItems));
   }
 }
public class ExtensionPointDeclarationRelatedItemLineMarkerProvider
    extends DevkitRelatedLineMarkerProviderBase {

  private static final NotNullFunction<ExtensionPointCandidate, Collection<? extends PsiElement>>
      CONVERTER = candidate -> Collections.singleton(candidate.pointer.getElement());

  private static final NotNullFunction<
          ExtensionPointCandidate, Collection<? extends GotoRelatedItem>>
      RELATED_ITEM_PROVIDER =
          candidate ->
              GotoRelatedItem.createItems(
                  Collections.singleton(candidate.pointer.getElement()), "DevKit");

  @Override
  protected void collectNavigationMarkers(
      @NotNull PsiElement element, Collection<? super RelatedItemLineMarkerInfo> result) {
    if (element instanceof PsiField) {
      process((PsiField) element, result);
    }
  }

  private static void process(
      PsiField psiField, Collection<? super RelatedItemLineMarkerInfo> result) {
    if (!isExtensionPointNameDeclarationField(psiField)) return;

    final PsiClass epClass = resolveExtensionPointClass(psiField);
    if (epClass == null) return;

    final String epName = resolveEpName(psiField);
    if (epName == null) return;

    ExtensionPointLocator locator = new ExtensionPointLocator(epClass);
    List<ExtensionPointCandidate> targets =
        ContainerUtil.filter(
            locator.findDirectCandidates(),
            new Condition<ExtensionPointCandidate>() {
              @Override
              public boolean value(ExtensionPointCandidate candidate) {
                return epName.equals(candidate.epName);
              }
            });

    final RelatedItemLineMarkerInfo<PsiElement> info =
        NavigationGutterIconBuilder.create(AllIcons.Nodes.Plugin, CONVERTER, RELATED_ITEM_PROVIDER)
            .setTargets(targets)
            .setPopupTitle("Choose Extension Point")
            .setTooltipText("Extension Point Declaration")
            .setAlignment(GutterIconRenderer.Alignment.RIGHT)
            .createLineMarkerInfo(psiField.getNameIdentifier());
    result.add(info);
  }

  @Nullable
  private static PsiClass resolveExtensionPointClass(PsiField psiField) {
    final PsiType typeParameter =
        PsiUtil.substituteTypeParameter(
            psiField.getType(), ExtensionPointName.class.getName(), 0, false);
    return PsiUtil.resolveClassInClassTypeOnly(typeParameter);
  }

  private static String resolveEpName(PsiField psiField) {
    final PsiExpression initializer = psiField.getInitializer();

    PsiExpressionList expressionList = null;
    if (initializer instanceof PsiMethodCallExpression) {
      expressionList = ((PsiMethodCallExpression) initializer).getArgumentList();
    } else if (initializer instanceof PsiNewExpression) {
      expressionList = ((PsiNewExpression) initializer).getArgumentList();
    }
    if (expressionList == null) return null;

    final PsiExpression[] expressions = expressionList.getExpressions();
    if (expressions.length != 1) return null;

    final PsiExpression epNameExpression = expressions[0];
    final PsiConstantEvaluationHelper helper =
        JavaPsiFacade.getInstance(psiField.getProject()).getConstantEvaluationHelper();
    final Object o = helper.computeConstantExpression(epNameExpression);
    return o instanceof String ? (String) o : null;
  }

  private static boolean isExtensionPointNameDeclarationField(PsiField psiField) {
    // *do* allow non-public
    if (!psiField.hasModifierProperty(PsiModifier.FINAL)
        || !psiField.hasModifierProperty(PsiModifier.STATIC)
        || psiField.hasModifierProperty(PsiModifier.ABSTRACT)) {
      return false;
    }

    if (!psiField.hasInitializer()) {
      return false;
    }

    final PsiExpression initializer = psiField.getInitializer();
    if (!(initializer instanceof PsiMethodCallExpression)
        && !(initializer instanceof PsiNewExpression)) {
      return false;
    }

    final PsiClass fieldClass = PsiTypesUtil.getPsiClass(psiField.getType());
    if (fieldClass == null) {
      return false;
    }

    return ExtensionPointName.class.getName().equals(fieldClass.getQualifiedName());
  }
}