public void childAdded()

in android/src/com/android/tools/idea/res/ResourceFolderRepository.java [1119:1296]


    public void childAdded(@NotNull PsiTreeChangeEvent event) {
      ResourceUpdateTracer.log(() -> getSimpleId(this) + ".childAdded " + pathForLogging(event.getFile()));
      try {
        PsiFile psiFile = event.getFile();
        if (psiFile != null && isRelevantFile(psiFile)) {
          VirtualFile virtualFile = psiFile.getVirtualFile();
          // If the file is currently being scanned, schedule a new scan to avoid a race condition
          // between the incremental update and the running scan.
          if (rescheduleScanIfRunning(virtualFile)) {
            return;
          }

          // Some child was added within a file.
          ResourceFolderType folderType = IdeResourcesUtil.getFolderType(psiFile);
          if (folderType != null && isResourceFile(psiFile)) {
            PsiElement child = event.getChild();
            PsiElement parent = event.getParent();
            if (folderType == VALUES) {
              if (child instanceof XmlTag) {
                XmlTag tag = (XmlTag)child;

                if (convertToPsiIfNeeded(psiFile, folderType)) {
                  return;
                }

                scheduleUpdate(() -> {
                  if (!tag.isValid()) {
                    scan(psiFile, folderType);
                    return;
                  }
                  if (isItemElement(tag)) {
                    ResourceItemSource<?> source = mySources.get(virtualFile);
                    if (source != null) {
                      assert source instanceof PsiResourceFile;
                      PsiResourceFile psiResourceFile = (PsiResourceFile)source;
                      String name = tag.getAttributeValue(ATTR_NAME);
                      if (isValidValueResourceName(name)) {
                        ResourceType type = getResourceTypeForResourceTag(tag);
                        if (type == ResourceType.STYLEABLE) {
                          // Can't handle declare styleable additions incrementally yet; need to update paired attr items.
                          scan(psiFile, folderType);
                          return;
                        }
                        if (type != null) {
                          PsiResourceItem item = PsiResourceItem.forXmlTag(name, type, ResourceFolderRepository.this, tag);
                          synchronized (ITEM_MAP_LOCK) {
                            getOrCreateMap(type).put(name, item);
                            psiResourceFile.addItem(item);
                            setModificationCount(ourModificationCounter.incrementAndGet());
                            invalidateParentCaches(ResourceFolderRepository.this, type);
                          }

                          return;
                        }
                      }
                    }
                  }

                  // See if you just added a new item inside a <style> or <array> or <declare-styleable> etc.
                  XmlTag parentTag = tag.getParentTag();
                  if (parentTag != null && getResourceTypeForResourceTag(parentTag) != null) {
                    // Yes just invalidate the corresponding cached value.
                    ResourceItem parentItem = findValueResourceItem(parentTag, psiFile);
                    if (parentItem instanceof PsiResourceItem) {
                      if (((PsiResourceItem)parentItem).recomputeValue()) {
                        setModificationCount(ourModificationCounter.incrementAndGet());
                      }
                      ResourceUpdateTracer.log(() -> getSimpleId(this) + ".childAdded " + pathForLogging(event.getFile()) +
                                                     " recomputed: " + parentItem);
                      return;
                    }
                  }

                  // Else: fall through and do full file rescan.
                  scan(psiFile, folderType);
                });
              }
              else if (parent instanceof XmlText) {
                // If the edit is within an item tag.
                XmlText text = (XmlText)parent;
                handleValueXmlTextEdit(text.getParentTag(), psiFile);
              }
              else if (child instanceof XmlText) {
                // If the edit is within an item tag.
                handleValueXmlTextEdit(parent, psiFile);
              }
              else if (!(parent instanceof XmlComment) && !(child instanceof XmlComment)) {
                scheduleScan(virtualFile, folderType);
              }
              // Can ignore comment edits or new comments.
              return;
            }
            else if (FolderTypeRelationship.isIdGeneratingFolderType(folderType) && psiFile.getFileType() == XmlFileType.INSTANCE) {
              if (parent instanceof XmlComment || child instanceof XmlComment) {
                return;
              }
              if (parent instanceof XmlText || (child instanceof XmlText && child.getText().trim().isEmpty())) {
                return;
              }

              if (parent instanceof XmlElement && child instanceof XmlElement) {
                if (child instanceof XmlTag) {
                  scheduleUpdate(() -> {
                    if (!child.isValid()) {
                      scan(psiFile, folderType);
                      return;
                    }
                    Map<ResourceType, ListMultimap<String, ResourceItem>> result = new HashMap<>();
                    List<PsiResourceItem> items = new ArrayList<>();
                    addIds(child, items, result);
                    if (!items.isEmpty()) {
                      ResourceItemSource<?> resourceFile = mySources.get(psiFile.getVirtualFile());
                      if (!(resourceFile instanceof PsiResourceFile)) {
                        scan(psiFile, folderType);
                        return;
                      }

                      PsiResourceFile psiResourceFile = (PsiResourceFile)resourceFile;
                      for (PsiResourceItem item : items) {
                        psiResourceFile.addItem(item);
                      }
                      commitToRepository(result);
                      setModificationCount(ourModificationCounter.incrementAndGet());
                      invalidateParentCaches(ResourceFolderRepository.this, ResourceType.ID);
                    }
                  });

                  return;
                }

                if (child instanceof XmlAttribute || parent instanceof XmlAttribute) {
                  // We check both because invalidation might come from XmlAttribute if it is inserted at once.
                  XmlAttribute attribute = parent instanceof XmlAttribute ? (XmlAttribute)parent : (XmlAttribute)child;

                  String id = createIdNameFromAttribute(attribute);
                  if (id != null) {
                    if (convertToPsiIfNeeded(psiFile, folderType)) {
                      return;
                    }

                    scheduleUpdate(() -> {
                      if (!attribute.isValid()) {
                        scan(psiFile, folderType);
                        return;
                      }
                      PsiResourceItem newIdResource =
                          PsiResourceItem.forXmlTag(id, ResourceType.ID, ResourceFolderRepository.this, attribute.getParent());
                      synchronized (ITEM_MAP_LOCK) {
                        ResourceItemSource<?> resourceFile = mySources.get(psiFile.getVirtualFile());
                        if (resourceFile != null) {
                          assert resourceFile instanceof PsiResourceFile;
                          PsiResourceFile psiResourceFile = (PsiResourceFile)resourceFile;
                          psiResourceFile.addItem(newIdResource);
                          ResourceUpdateTracer.log(() -> getSimpleId(this) + ": Adding id/" + newIdResource.getName());
                          getOrCreateMap(ResourceType.ID).put(newIdResource.getName(), newIdResource);
                          setModificationCount(ourModificationCounter.incrementAndGet());
                          invalidateParentCaches(ResourceFolderRepository.this, ResourceType.ID);
                        }
                      }
                    });

                    return;
                  }
                }
              }
            }
            else if (folderType == FONT) {
              clearFontCache(psiFile.getVirtualFile());
            }
          }
        }

        myIgnoreChildrenChanged = true;
      }
      finally {
        ResourceUpdateTracer.log(() -> getSimpleId(this) + ".childAdded " + pathForLogging(event.getFile()) + " end");
      }
    }