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");
}