/**
   * Checks if package is indexed.
   *
   * @param packageName package name
   * @return checking result
   */
  public boolean isKnownPackage(String packageName) {
    String canonicalPackageName = PerlPackageUtil.getCanonicalPackageName(packageName);

    if (!indexSnapshotDone) makeIndexSnapshot();

    return KNOWN_PACKAGES.contains(canonicalPackageName);
  }
  /**
   * Makes index snapshot hashsets
   *
   * @return result
   */
  public synchronized boolean makeIndexSnapshot() {
    if (!indexSnapshotDone && !DumbService.isDumb(myProject)) {
      KNOWN_SUBS.addAll(PerlSubUtil.getDeclaredSubsNames(myProject));
      KNOWN_SUBS.addAll(PerlSubUtil.getDefinedSubsNames(myProject));
      KNOWN_SUBS.addAll(PerlGlobUtil.getDefinedGlobsNames(myProject));

      KNOWN_PACKAGES.addAll(PerlPackageUtil.getDefinedPackageNames(myProject));
      indexSnapshotDone = true;
    }
    return indexSnapshotDone;
  }
  @Override
  public String getContextPackageNameHeavy() {
    //		System.err.println("Guessing type for method " + getText() + " at " + getTextOffset());

    PsiElement parent = getParent();
    PsiElement grandParent = parent == null ? null : parent.getParent();

    if (grandParent instanceof PsiPerlDerefExpr) {
      return ((PsiPerlDerefExpr) grandParent).getPreviousElementType(parent);
    }

    return PerlPackageUtil.getContextPackageName(this);
  }
  @Override
  protected void collectNavigationMarkers(
      @NotNull PsiElement element, Collection<? super RelatedItemLineMarkerInfo> result) {
    if (element instanceof PerlNamespaceDefinition) {
      PsiElement nameIdentifier = ((PerlNamespaceDefinition) element).getNameIdentifier();
      if (nameIdentifier == null) nameIdentifier = element;

      List<PerlNamespaceDefinition> parentNamespaces =
          ((PerlNamespaceDefinition) element).getParentNamespaceDefinitions();
      if (parentNamespaces.size() > 0) {
        NavigationGutterIconBuilder<PsiElement> builder =
            NavigationGutterIconBuilder.create(AllIcons.Gutter.ImplementingMethod)
                .setTargets(parentNamespaces)
                .setTooltipText("Parent classes");

        result.add(builder.createLineMarkerInfo(nameIdentifier));
      }

      Collection<PerlNamespaceDefinition> childNamespaces =
          ((PerlNamespaceDefinition) element).getChildNamespaceDefinitions();
      if (childNamespaces.size() > 0) {
        NavigationGutterIconBuilder<PsiElement> builder =
            NavigationGutterIconBuilder.create(AllIcons.Gutter.ImplementedMethod)
                .setTargets(childNamespaces)
                .setTooltipText("Subclasses");

        result.add(builder.createLineMarkerInfo(nameIdentifier));
      }

    } else if (element instanceof PerlSubDefinitionBase
        && ((PerlSubDefinitionBase) element).isMethod()) {
      PerlNamespaceDefinition containingNamespace =
          PsiTreeUtil.getParentOfType(element, PerlNamespaceDefinition.class);
      if (containingNamespace != null) {
        final String packageName = ((PerlSubDefinitionBase) element).getPackageName();
        final String subName = ((PerlSubDefinitionBase) element).getSubName();
        PsiElement nameIdentifier = ((PerlSubDefinitionBase) element).getNameIdentifier();
        if (nameIdentifier == null) nameIdentifier = element;

        if (StringUtil.isNotEmpty(packageName) && StringUtil.isNotEmpty(subName)) {
          Collection<PsiElement> superMethods =
              PerlMro.resolveSub(element.getProject(), packageName, subName, true);
          if (superMethods.size() > 0) {
            NavigationGutterIconBuilder<PsiElement> builder =
                NavigationGutterIconBuilder.create(AllIcons.Gutter.OverridingMethod)
                    .setTargets(superMethods)
                    .setTooltipText("Overriding method");

            result.add(builder.createLineMarkerInfo(nameIdentifier));
          }

          final List<PerlSubBase> overridingSubs = new ArrayList<PerlSubBase>();

          PerlPackageUtil.processChildNamespacesSubs(
              containingNamespace,
              null,
              new Processor<PerlSubBase>() {
                @Override
                public boolean process(PerlSubBase perlSubBase) {
                  String subBaseName = perlSubBase.getSubName();
                  if (StringUtil.isNotEmpty(subBaseName)
                      && subName.equals(subBaseName)
                      && perlSubBase.isMethod()) {
                    overridingSubs.add(perlSubBase);
                    return false;
                  }
                  return true;
                }
              });

          if (overridingSubs.size() > 0) {
            NavigationGutterIconBuilder<PsiElement> builder =
                NavigationGutterIconBuilder.create(AllIcons.Gutter.OverridenMethod)
                    .setTargets(overridingSubs)
                    .setTooltipText("Overriden methods");

            result.add(builder.createLineMarkerInfo(nameIdentifier));
          }
        }
      }
    }
  }
 @Override
 public String getContextPackageName() {
   return PerlPackageUtil.getContextPackageName(this);
 }
  /**
   * Parses invocable method As input we may have: PACKAGE_IDENTIFIER IDENTIFIER Foo::sub IDENTIFIER
   * PACKAGE_IDENTIFIER sub Foo:: IDENTIFIER IDENTIFIER sub Foo
   *
   * @param b PerlBuilder
   * @param l parsing level
   * @return parsing result
   */
  public static boolean parseMethod(PsiBuilder b, int l) {
    IElementType currentTokenType = b.getTokenType();
    IElementType nextTokenType = b.lookAhead(1);

    assert b instanceof PerlBuilder;

    // can be
    // 	Foo::method
    //  Foo::Bar
    if (PACKAGE_TOKENS.contains(currentTokenType) && CONVERTABLE_TOKENS.contains(nextTokenType)) {
      PerlTokenData nextTokenData = ((PerlBuilder) b).lookupToken(1);
      PerlTokenData nextNextTokenData = ((PerlBuilder) b).lookupToken(2);

      IElementType nextNextTokenType =
          nextNextTokenData == null ? null : nextNextTokenData.getTokenType();

      String canonicalPackageName = PerlPackageUtil.getCanonicalPackageName(b.getTokenText());
      String potentialSubName = canonicalPackageName + "::" + nextTokenData.getTokenText();

      if (nextNextTokenType == LEFT_PAREN // Package::Identifier( - what can it be?
          || ((PerlBuilder) b).isKnownSub(potentialSubName) // we know this sub
          || !((PerlBuilder) b).isKnownPackage(potentialSubName)) // we don't know such package
      return convertPackageIdentifier(b, l) && convertIdentifier(b, l, SUB);
      else return false;
    }
    // 	method
    else if (CONVERTABLE_TOKENS.contains(currentTokenType)) {
      PerlTokenData prevTokenData = ((PerlBuilder) b).lookupToken(-1);

      // ->sub
      if (prevTokenData != null && prevTokenData.getTokenType() == OPERATOR_DEREFERENCE)
        return convertIdentifier(b, l, SUB);
      // may be
      // 	method Foo::
      //	method Foo::Bar
      //  method Foo::othermethod
      else if (PACKAGE_TOKENS.contains(nextTokenType)) {
        IElementType nextNextTokenType = b.lookAhead(2);

        // sub Foo::->method
        if (nextNextTokenType == OPERATOR_DEREFERENCE) return convertIdentifier(b, l, SUB);
        // identifier Package::identifier
        else if (CONVERTABLE_TOKENS.contains(nextNextTokenType)) {

          // identifier Package::identifier->
          if (b.lookAhead(3) == OPERATOR_DEREFERENCE) return convertIdentifier(b, l, SUB);

          PerlTokenData nextTokenData = ((PerlBuilder) b).lookupToken(1);
          PerlTokenData nextNextTokenData = ((PerlBuilder) b).lookupToken(2);

          String packageOrSub =
              PerlPackageUtil.getCanonicalPackageName(nextTokenData.getTokenText())
                  + "::"
                  + nextNextTokenData.getTokenText();

          if (((PerlBuilder) b).isKnownSub(packageOrSub)) return convertIdentifier(b, l, SUB);
          else if (((PerlBuilder) b).isKnownPackage(packageOrSub))
            return convertIdentifier(b, l, SUB) && mergePackageName(b, l);
          return convertIdentifier(b, l, SUB);
        } else
          // it's method Package::
          return convertIdentifier(b, l, SUB) && convertPackageIdentifier(b, l);
      }
      // may be
      // 	method Foo
      else if (CONVERTABLE_TOKENS.contains(nextTokenType)
          && b.lookAhead(2) != OPERATOR_DEREFERENCE) {
        PerlTokenData nextTokenData = ((PerlBuilder) b).lookupToken(1);

        String potentialSubName = nextTokenData.getTokenText() + "::" + b.getTokenText();
        if (((PerlBuilder) b).isKnownSub(potentialSubName))
          return convertIdentifier(b, l, SUB) && convertIdentifier(b, l, PACKAGE);
        else return convertIdentifier(b, l, SUB);
      }
      // KnownPackage->
      else if (nextTokenType == OPERATOR_DEREFERENCE
          && ((PerlBuilder) b).isKnownPackage(b.getTokenText())) return false;
      // it's just sub
      else return convertIdentifier(b, l, SUB);
    }

    return false;
  }