@Nullable
 @Override
 public RefEntity getReference(final String type, final String fqName) {
   for (RefManagerExtension extension : myExtensions.values()) {
     final RefEntity refEntity = extension.getReference(type, fqName);
     if (refEntity != null) return refEntity;
   }
   if (SmartRefElementPointer.FILE.equals(type)) {
     return RefFileImpl.fileFromExternalName(this, fqName);
   }
   if (SmartRefElementPointer.MODULE.equals(type)) {
     return RefModuleImpl.moduleFromName(this, fqName);
   }
   if (SmartRefElementPointer.PROJECT.equals(type)) {
     return getRefProject();
   }
   if (SmartRefElementPointer.DIR.equals(type)) {
     String url =
         VfsUtilCore.pathToUrl(PathMacroManager.getInstance(getProject()).expandPath(fqName));
     VirtualFile vFile = VirtualFileManager.getInstance().findFileByUrl(url);
     if (vFile != null) {
       final PsiDirectory dir = PsiManager.getInstance(getProject()).findDirectory(vFile);
       return getReference(dir);
     }
   }
   return null;
 }
 private boolean belongsToScope(final PsiElement psiElement, final boolean ignoreScope) {
   if (psiElement == null || !psiElement.isValid()) return false;
   if (psiElement instanceof PsiCompiledElement) return false;
   final PsiFile containingFile =
       ApplicationManager.getApplication()
           .runReadAction(
               new Computable<PsiFile>() {
                 @Override
                 public PsiFile compute() {
                   return psiElement.getContainingFile();
                 }
               });
   if (containingFile == null) {
     return false;
   }
   for (RefManagerExtension extension : myExtensions.values()) {
     if (!extension.belongsToScope(psiElement)) return false;
   }
   final Boolean inProject =
       ApplicationManager.getApplication()
           .runReadAction(
               new Computable<Boolean>() {
                 @Override
                 public Boolean compute() {
                   return psiElement.getManager().isInProject(psiElement);
                 }
               });
   return inProject.booleanValue()
       && (ignoreScope || getScope() == null || getScope().contains(psiElement));
 }
 @NotNull
 @Override
 public RefEntity getRefinedElement(@NotNull RefEntity ref) {
   for (RefManagerExtension extension : myExtensions.values()) {
     ref = extension.getRefinedElement(ref);
   }
   return ref;
 }
 @Override
 public void visitElement(PsiElement element) {
   final RefManagerExtension extension = getExtension(element.getLanguage());
   if (extension != null) {
     extension.visitElement(element);
   }
   for (PsiElement aChildren : element.getChildren()) {
     aChildren.accept(this);
   }
 }
  @Override
  public Element export(
      @NotNull RefEntity refEntity, @NotNull final Element element, final int actualLine) {
    refEntity = getRefinedElement(refEntity);

    Element problem = new Element("problem");

    if (refEntity instanceof RefElement) {
      final RefElement refElement = (RefElement) refEntity;
      final SmartPsiElementPointer pointer = refElement.getPointer();
      PsiFile psiFile = pointer.getContainingFile();
      if (psiFile == null) return null;

      Element fileElement = new Element("file");
      Element lineElement = new Element("line");
      final VirtualFile virtualFile = psiFile.getVirtualFile();
      LOG.assertTrue(virtualFile != null);
      fileElement.addContent(virtualFile.getUrl());

      if (actualLine == -1) {
        final Document document =
            PsiDocumentManager.getInstance(pointer.getProject()).getDocument(psiFile);
        LOG.assertTrue(document != null);
        final Segment range = pointer.getRange();
        lineElement.addContent(
            String.valueOf(
                range != null ? document.getLineNumber(range.getStartOffset()) + 1 : -1));
      } else {
        lineElement.addContent(String.valueOf(actualLine));
      }

      problem.addContent(fileElement);
      problem.addContent(lineElement);

      appendModule(problem, refElement.getModule());
    } else if (refEntity instanceof RefModule) {
      final RefModule refModule = (RefModule) refEntity;
      final VirtualFile moduleFile = refModule.getModule().getModuleFile();
      final Element fileElement = new Element("file");
      fileElement.addContent(moduleFile != null ? moduleFile.getUrl() : refEntity.getName());
      problem.addContent(fileElement);
      appendModule(problem, refModule);
    }

    for (RefManagerExtension extension : myExtensions.values()) {
      extension.export(refEntity, problem);
    }

    new SmartRefElementPointerImpl(refEntity, true).writeExternal(problem);
    element.addContent(problem);
    return problem;
  }
 @Override
 public void iterate(@NotNull RefVisitor visitor) {
   for (RefElement refElement : getSortedElements()) {
     refElement.accept(visitor);
   }
   if (myModules != null) {
     for (RefModule refModule : myModules.values()) {
       refModule.accept(visitor);
     }
   }
   for (RefManagerExtension extension : myExtensions.values()) {
     extension.iterate(visitor);
   }
 }
  public void cleanup() {
    myScope = null;
    myRefProject = null;
    synchronized (myRefTable) {
      myRefTable.clear();
      mySortedRefs = null;
    }
    myModules.clear();
    myContext = null;

    myGraphAnnotators.clear();
    for (RefManagerExtension extension : myExtensions.values()) {
      extension.cleanup();
    }
  }
  @Nullable
  public RefElement getReference(final PsiElement elem, final boolean ignoreScope) {
    if (ApplicationManager.getApplication()
        .runReadAction(
            new Computable<Boolean>() {
              @Override
              public Boolean compute() {
                return elem == null
                    || !elem.isValid()
                    || elem instanceof LightElement
                    || !(elem instanceof PsiDirectory) && !belongsToScope(elem, ignoreScope);
              }
            })) {
      return null;
    }

    return getFromRefTableOrCache(
        elem,
        () ->
            ApplicationManager.getApplication()
                .runReadAction(
                    new Computable<RefElementImpl>() {
                      @Override
                      @Nullable
                      public RefElementImpl compute() {
                        final RefManagerExtension extension = getExtension(elem.getLanguage());
                        if (extension != null) {
                          final RefElement refElement = extension.createRefElement(elem);
                          if (refElement != null) return (RefElementImpl) refElement;
                        }
                        if (elem instanceof PsiFile) {
                          return new RefFileImpl((PsiFile) elem, RefManagerImpl.this);
                        }
                        if (elem instanceof PsiDirectory) {
                          return new RefDirectoryImpl((PsiDirectory) elem, RefManagerImpl.this);
                        }
                        return null;
                      }
                    }),
        element -> {
          element.initialize();
          for (RefManagerExtension each : myExtensions.values()) {
            each.onEntityInitialized(element, elem);
          }
          fireNodeInitialized(element);
        });
  }
  @Override
  @Nullable
  public String getGroupName(final RefElement entity) {
    for (RefManagerExtension extension : myExtensions.values()) {
      final String groupName = extension.getGroupName(entity);
      if (groupName != null) return groupName;
    }

    final LinkedList<String> containingDirs = new LinkedList<>();
    RefEntity parent = entity.getOwner();
    while (parent != null && !(parent instanceof RefDirectory)) {
      parent = parent.getOwner();
    }
    while (parent instanceof RefDirectory) {
      containingDirs.addFirst(parent.getName());
      parent = parent.getOwner();
    }
    return containingDirs.isEmpty() ? null : StringUtil.join(containingDirs, File.separator);
  }
 @Override
 @Nullable
 public String getType(final RefEntity ref) {
   for (RefManagerExtension extension : myExtensions.values()) {
     final String type = extension.getType(ref);
     if (type != null) return type;
   }
   if (ref instanceof RefFile) {
     return SmartRefElementPointer.FILE;
   }
   if (ref instanceof RefModule) {
     return SmartRefElementPointer.MODULE;
   }
   if (ref instanceof RefProject) {
     return SmartRefElementPointer.PROJECT;
   }
   if (ref instanceof RefDirectory) {
     return SmartRefElementPointer.DIR;
   }
   return null;
 }
 public RefManagerImpl(
     @NotNull Project project,
     @Nullable AnalysisScope scope,
     @NotNull GlobalInspectionContext context) {
   myProject = project;
   myScope = scope;
   myContext = context;
   myPsiManager = PsiManager.getInstance(project);
   myRefProject = new RefProjectImpl(this);
   for (InspectionExtensionsFactory factory :
       Extensions.getExtensions(InspectionExtensionsFactory.EP_NAME)) {
     final RefManagerExtension extension = factory.createRefManagerExtension(this);
     if (extension != null) {
       myExtensions.put(extension.getID(), extension);
       myLanguageExtensions.put(extension.getLanguage(), extension);
     }
   }
   if (scope != null) {
     for (Module module : ModuleManager.getInstance(getProject()).getModules()) {
       getRefModule(module);
     }
   }
 }
  void removeReference(@NotNull RefElement refElem) {
    final PsiElement element = refElem.getElement();
    final RefManagerExtension extension =
        element != null ? getExtension(element.getLanguage()) : null;
    if (extension != null) {
      extension.removeReference(refElem);
    }

    synchronized (myRefTable) {
      mySortedRefs = null;
      if (element != null && myRefTable.remove(createAnchor(element)) != null) return;

      // PsiElement may have been invalidated and new one returned by getElement() is different so
      // we need to do this stuff.
      for (Map.Entry<PsiAnchor, RefElement> entry : myRefTable.entrySet()) {
        RefElement value = entry.getValue();
        PsiAnchor anchor = entry.getKey();
        if (value == refElem) {
          myRefTable.remove(anchor);
          break;
        }
      }
    }
  }