@NotNull
  private List<AnnotationData> doCollect(
      @NotNull PsiModifierListOwner listOwner, boolean onlyWritable) {
    final List<PsiFile> files = findExternalAnnotationsFiles(listOwner);
    if (files == null) {
      return NO_DATA;
    }
    SmartList<AnnotationData> result = new SmartList<AnnotationData>();
    String externalName = getExternalName(listOwner, false);
    if (externalName == null) return NO_DATA;

    for (PsiFile file : files) {
      if (!file.isValid()) continue;
      if (onlyWritable && !file.isWritable()) continue;

      MostlySingularMultiMap<String, AnnotationData> fileData = getDataFromFile(file);

      ContainerUtil.addAll(result, fileData.get(externalName));
    }
    if (result.isEmpty()) {
      return NO_DATA;
    }
    result.trimToSize();
    return result;
  }
  @Override
  @Nullable
  public List<PsiFile> findExternalAnnotationsFiles(@NotNull PsiModifierListOwner listOwner) {
    final PsiFile containingFile = listOwner.getContainingFile();
    if (!(containingFile instanceof PsiJavaFile)) {
      return null;
    }
    final PsiJavaFile javaFile = (PsiJavaFile) containingFile;
    final String packageName = javaFile.getPackageName();
    final VirtualFile virtualFile = containingFile.getVirtualFile();
    if (virtualFile == null) return null;

    final List<PsiFile> files = myExternalAnnotations.get(virtualFile);
    if (files == NULL_LIST) return null;
    if (files != null) {
      boolean allValid = true;
      for (PsiFile file : files) {
        allValid &= file.isValid();
      }
      if (allValid) {
        return files;
      }
    }

    if (virtualFile == null) {
      return null;
    }

    Set<PsiFile> possibleAnnotationsXmls = new THashSet<PsiFile>();
    for (VirtualFile root : getExternalAnnotationsRoots(virtualFile)) {
      final VirtualFile ext =
          root.findFileByRelativePath(packageName.replace('.', '/') + "/" + ANNOTATIONS_XML);
      if (ext == null) continue;
      final PsiFile psiFile = myPsiManager.findFile(ext);
      if (psiFile == null) continue;
      possibleAnnotationsXmls.add(psiFile);
    }
    List<PsiFile> result;
    if (possibleAnnotationsXmls.isEmpty()) {
      myExternalAnnotations.put(virtualFile, NULL_LIST);
      result = null;
    } else {
      result = new SmartList<PsiFile>(possibleAnnotationsXmls);
      // sorting by writability: writable go first
      Collections.sort(
          result,
          new Comparator<PsiFile>() {
            @Override
            public int compare(PsiFile f1, PsiFile f2) {
              boolean w1 = f1.isWritable();
              boolean w2 = f2.isWritable();
              if (w1 == w2) {
                return 0;
              }
              return w1 ? -1 : 1;
            }
          });

      myExternalAnnotations.put(virtualFile, result);
    }
    return result;
  }