private void scan()

in android/src/com/android/tools/idea/res/ResourceFolderRepository.java [817:968]


  private void scan(@NotNull PsiFile psiFile, @NotNull ResourceFolderType folderType) {
    ProgressManager.checkCanceled();

    if (!isResourceFile(psiFile) || !isRelevantFile(psiFile) || psiFile.getProject().isDisposed()) {
      return;
    }

    ResourceUpdateTracer.log(() -> getSimpleId(this) + ".scan " + pathForLogging(psiFile));
    if (LOG.isDebugEnabled()) {
      LOG.debug("Rescanning ", psiFile);
    }

    Map<ResourceType, ListMultimap<String, ResourceItem>> result = new HashMap<>();

    PsiFile file = psiFile;
    if (folderType == VALUES) {
      // For unit test tracking purposes only.
      fileRescans++;

      // First delete out the previous items.
      ResourceItemSource<?> source = mySources.remove(file.getVirtualFile());
      boolean removed = false;
      if (source != null) {
        removed = removeItemsFromSource(source);
      }

      file = ensureValid(file);
      boolean added = false;
      if (file != null) {
        // Add items for this file.
        PsiDirectory parent = file.getParent();
        assert parent != null; // Since we have a folder type.
        PsiDirectory fileParent = psiFile.getParent();
        if (fileParent != null) {
          FolderConfiguration folderConfiguration = FolderConfiguration.getConfigForFolder(fileParent.getName());
          if (folderConfiguration != null) {
            ProgressManager.checkCanceled();
            added = scanValueFileAsPsi(result, file, folderConfiguration);
          }
        }
      }

      if (added || removed) {
        // TODO: Consider doing a deeper diff of the changes to the resource items
        //       to determine if the removed and added items actually differ.
        setModificationCount(ourModificationCounter.incrementAndGet());
        invalidateParentCaches(this, ResourceType.values());
      }
    } else if (checkResourceFilename(file, folderType)) {
      ResourceItemSource<?> source = mySources.get(file.getVirtualFile());
      if (source instanceof PsiResourceFile && file.getFileType() == XmlFileType.INSTANCE) {
        // If the old file was a PsiResourceFile for an XML file, we can update ID ResourceItems in place.
        PsiResourceFile psiResourceFile = (PsiResourceFile)source;
        // Already seen this file; no need to do anything unless it's an XML file with generated ids;
        // in that case we may need to update the id's.
        if (FolderTypeRelationship.isIdGeneratingFolderType(folderType)) {
          // For unit test tracking purposes only.
          fileRescans++;

          // We've already seen this resource, so no change in the ResourceItem for the
          // file itself (e.g. @layout/foo from layout-land/foo.xml). However, we may have
          // to update the id's:
          Set<String> idsBefore = new HashSet<>();
          synchronized (ITEM_MAP_LOCK) {
            ListMultimap<String, ResourceItem> idMultimap = myResourceTable.get(ResourceType.ID);
            if (idMultimap != null) {
              List<PsiResourceItem> idItems = new ArrayList<>();
              for (PsiResourceItem item : psiResourceFile) {
                if (item.getType() == ResourceType.ID) {
                  idsBefore.add(item.getName());
                  idItems.add(item);
                }
              }
              for (String id : idsBefore) {
                // TODO(sprigogin): Simplify this code since the following comment is out of date.
                // Note that ResourceFile has a flat map (not a multimap) so it doesn't
                // record all items (unlike the myItems map) so we need to remove the map
                // items manually, can't just do map.remove(item.getName(), item)
                List<ResourceItem> mapItems = idMultimap.get(id);
                if (!mapItems.isEmpty()) {
                  List<ResourceItem> toDelete = new ArrayList<>(mapItems.size());
                  for (ResourceItem mapItem : mapItems) {
                    if (mapItem instanceof PsiResourceItem && ((PsiResourceItem)mapItem).getSourceFile() == psiResourceFile) {
                      toDelete.add(mapItem);
                    }
                  }
                  for (ResourceItem item : toDelete) {
                    idMultimap.remove(item.getName(), item);
                  }
                }
              }
              for (PsiResourceItem item : idItems) {
                psiResourceFile.removeItem(item);
              }
            }
          }

          // Add items for this file.
          List<PsiResourceItem> idItems = new ArrayList<>();
          file = ensureValid(file);
          if (file != null) {
            ProgressManager.checkCanceled();
            addIds(file, idItems, result);
          }
          if (!idItems.isEmpty()) {
            for (PsiResourceItem item : idItems) {
              psiResourceFile.addItem(item);
            }
          }

          // Identities may have changed even if the ids are the same, so update maps.
          setModificationCount(ourModificationCounter.incrementAndGet());
          invalidateParentCaches(this, ResourceType.ID);
        }
      } else {
        // Either we're switching to PSI or the file is not XML (image or font), which is not incremental.
        // Remove old items first, rescan below to add back, but with a possibly different multimap list order.
        if (source != null) {
          removeItemsFromSource(source);
        }
        // For unit test tracking purposes only.
        fileRescans++;

        PsiDirectory parent = file.getParent();
        assert parent != null; // Since we have a folder type.

        ResourceType type = FolderTypeRelationship.getNonIdRelatedResourceType(folderType);
        boolean idGeneratingFolder = FolderTypeRelationship.isIdGeneratingFolderType(folderType);

        ProgressManager.checkCanceled();
        clearLayoutlibCaches(file.getVirtualFile(), folderType);

        file = ensureValid(file);
        if (file != null) {
          PsiDirectory fileParent = psiFile.getParent();
          if (fileParent != null) {
            FolderConfiguration folderConfiguration = FolderConfiguration.getConfigForFolder(fileParent.getName());
            if (folderConfiguration != null) {
              boolean idGeneratingFile = idGeneratingFolder && file.getFileType() == XmlFileType.INSTANCE;
              ProgressManager.checkCanceled();
              scanFileResourceFileAsPsi(file, folderType, folderConfiguration, type, idGeneratingFile, result);
            }
          }
          setModificationCount(ourModificationCounter.incrementAndGet());
          invalidateParentCaches(this, ResourceType.values());
        }
      }
    }

    commitToRepository(result);
    ResourceUpdateTracer.log(() -> getSimpleId(this) + ".scan " + pathForLogging(psiFile) + " end");
  }