@Override
 public boolean deannotate(
     @NotNull final PsiModifierListOwner listOwner, @NotNull final String annotationFQN) {
   try {
     final List<XmlFile> files = findExternalAnnotationsXmlFiles(listOwner);
     if (files == null) {
       return false;
     }
     for (XmlFile file : files) {
       if (!file.isValid()) {
         continue;
       }
       final XmlDocument document = file.getDocument();
       if (document == null) {
         continue;
       }
       final XmlTag rootTag = document.getRootTag();
       if (rootTag == null) {
         continue;
       }
       final String externalName = getExternalName(listOwner, false);
       final String oldExternalName = getNormalizedExternalName(listOwner);
       for (final XmlTag tag : rootTag.getSubTags()) {
         final String className = tag.getAttributeValue("name");
         if (!Comparing.strEqual(className, externalName)
             && !Comparing.strEqual(className, oldExternalName)) {
           continue;
         }
         for (XmlTag annotationTag : tag.getSubTags()) {
           if (!Comparing.strEqual(annotationTag.getAttributeValue("name"), annotationFQN)) {
             continue;
           }
           if (ReadonlyStatusHandler.getInstance(myPsiManager.getProject())
               .ensureFilesWritable(file.getVirtualFile())
               .hasReadonlyFiles()) {
             return false;
           }
           try {
             annotationTag.delete();
             if (tag.getSubTags().length == 0) {
               tag.delete();
             }
           } catch (IncorrectOperationException e) {
             LOG.error(e);
           }
           return true;
         }
         return false;
       }
     }
     return false;
   } finally {
     dropCache();
   }
 }
  @NotNull
  private static Map<Module, String> collectJpsPluginModules(@NotNull Module module) {
    XmlFile pluginXml = PluginModuleType.getPluginXml(module);
    if (pluginXml == null) return Collections.emptyMap();

    DomFileElement<IdeaPlugin> fileElement =
        DomManager.getDomManager(module.getProject()).getFileElement(pluginXml, IdeaPlugin.class);
    if (fileElement == null) return Collections.emptyMap();

    Map<Module, String> jpsPluginToOutputPath = new HashMap<Module, String>();
    IdeaPlugin plugin = fileElement.getRootElement();
    List<Extensions> extensions = plugin.getExtensions();
    for (Extensions extensionGroup : extensions) {
      XmlTag extensionsTag = extensionGroup.getXmlTag();
      String defaultExtensionNs = extensionsTag.getAttributeValue("defaultExtensionNs");
      for (XmlTag tag : extensionsTag.getSubTags()) {
        String name = tag.getLocalName();
        String qualifiedName = defaultExtensionNs != null ? defaultExtensionNs + "." + name : name;
        if (CompileServerPlugin.EP_NAME.getName().equals(qualifiedName)) {
          String classpath = tag.getAttributeValue("classpath");
          if (classpath != null) {
            for (String path : StringUtil.split(classpath, ";")) {
              String moduleName = FileUtil.getNameWithoutExtension(PathUtil.getFileName(path));
              Module jpsModule =
                  ModuleManager.getInstance(module.getProject()).findModuleByName(moduleName);
              if (jpsModule != null) {
                jpsPluginToOutputPath.put(jpsModule, path);
              }
            }
          }
        }
      }
    }
    return jpsPluginToOutputPath;
  }
  public static List<XmlTag> findSubTags(
      @NotNull final XmlTag tag, final EvaluatedXmlName name, final XmlFile file) {
    if (!tag.isValid()) {
      throw new AssertionError("Invalid tag");
    }
    final XmlTag[] tags = tag.getSubTags();
    if (tags.length == 0) {
      return Collections.emptyList();
    }

    return ContainerUtil.findAll(
        tags,
        childTag -> {
          try {
            return isNameSuitable(
                name, childTag.getLocalName(), childTag.getName(), childTag.getNamespace(), file);
          } catch (PsiInvalidElementAccessException e) {
            if (!childTag.isValid()) {
              LOG.error(
                  "tag.getSubTags() returned invalid, "
                      + "tag="
                      + tag
                      + ", "
                      + "containing file: "
                      + tag.getContainingFile()
                      + "subTag.parent="
                      + childTag.getNode().getTreeParent());
              return false;
            }
            throw e;
          }
        });
  }
  private static XmlTag getIndexedTag(XmlTag parent, Integer index) {
    if (index == null) return parent;

    XmlTag[] children = parent.getSubTags();
    if (index < 0 || index >= children.length) return null;
    return children[index];
  }
  private static @Nullable XmlTag findSpecialTag(
      @NonNls String name,
      @NonNls String specialName,
      XmlTag rootTag,
      XmlNSDescriptorImpl descriptor,
      HashSet<XmlTag> visited) {
    XmlNSDescriptorImpl nsDescriptor = getNSDescriptorToSearchIn(rootTag, name, descriptor);

    if (nsDescriptor != descriptor) {
      final XmlDocument document =
          nsDescriptor.getDescriptorFile() != null
              ? nsDescriptor.getDescriptorFile().getDocument()
              : null;
      if (document == null) return null;

      return findSpecialTag(
          XmlUtil.findLocalNameByQualifiedName(name),
          specialName,
          document.getRootTag(),
          nsDescriptor,
          visited);
    }

    if (visited == null) visited = new HashSet<XmlTag>(1);
    else if (visited.contains(rootTag)) return null;
    visited.add(rootTag);

    XmlTag[] tags = rootTag.getSubTags();

    return findSpecialTagIn(tags, specialName, name, rootTag, descriptor, visited);
  }
  private void doFix() throws IncorrectOperationException {
    final XmlTag tag = PsiTreeUtil.getParentOfType(myReference.getElement(), XmlTag.class);
    assert tag != null;
    final XmlTag defineTag =
        tag.createChildTag("define", ApplicationLoader.RNG_NAMESPACE, "\n \n", false);
    defineTag.setAttribute("name", myReference.getCanonicalText());

    final RngGrammar grammar = ((DefinitionReference) myReference).getScope();
    if (grammar == null) return;
    final XmlTag root = grammar.getXmlTag();
    if (root == null) return;

    final XmlTag[] tags = root.getSubTags();
    for (XmlTag xmlTag : tags) {
      if (PsiTreeUtil.isAncestor(xmlTag, tag, false)) {
        final XmlElementFactory ef = XmlElementFactory.getInstance(tag.getProject());
        final XmlText text = ef.createDisplayText(" ");
        final PsiElement e = root.addAfter(text, xmlTag);

        root.addAfter(defineTag, e);
        return;
      }
    }
    root.add(defineTag);
  }
  public static List<DomElement> getDefinedChildren(
      @NotNull final DomElement parent, final boolean tags, final boolean attributes) {
    if (parent instanceof MergedObject) {
      final SmartList<DomElement> result = new SmartList<>();
      parent.acceptChildren(
          new DomElementVisitor() {
            @Override
            public void visitDomElement(final DomElement element) {
              if (hasXml(element)) {
                result.add(element);
              }
            }
          });
      return result;
    }

    ProgressManager.checkCanceled();

    if (parent instanceof GenericAttributeValue) return Collections.emptyList();

    if (parent instanceof DomFileElement) {
      final DomFileElement element = (DomFileElement) parent;
      return tags ? Arrays.asList(element.getRootElement()) : Collections.<DomElement>emptyList();
    }

    final XmlElement xmlElement = parent.getXmlElement();
    if (xmlElement instanceof XmlTag) {
      XmlTag tag = (XmlTag) xmlElement;
      final DomManager domManager = parent.getManager();
      final SmartList<DomElement> result = new SmartList<>();
      if (attributes) {
        for (final XmlAttribute attribute : tag.getAttributes()) {
          if (!attribute.isValid()) {
            LOG.error("Invalid attr: parent.valid=" + tag.isValid());
            continue;
          }
          GenericAttributeValue element = domManager.getDomElement(attribute);
          if (checkHasXml(attribute, element)) {
            ContainerUtil.addIfNotNull(result, element);
          }
        }
      }
      if (tags) {
        for (final XmlTag subTag : tag.getSubTags()) {
          if (!subTag.isValid()) {
            LOG.error("Invalid subtag: parent.valid=" + tag.isValid());
            continue;
          }
          DomElement element = domManager.getDomElement(subTag);
          if (checkHasXml(subTag, element)) {
            ContainerUtil.addIfNotNull(result, element);
          }
        }
      }
      return result;
    }
    return Collections.emptyList();
  }
 private void annotateExternally(
     @NotNull PsiModifierListOwner listOwner,
     @NotNull String annotationFQName,
     @Nullable final XmlFile xmlFile,
     @NotNull PsiFile codeUsageFile,
     PsiNameValuePair[] values) {
   if (xmlFile == null) return;
   try {
     final XmlDocument document = xmlFile.getDocument();
     if (document != null) {
       final XmlTag rootTag = document.getRootTag();
       final String externalName = getExternalName(listOwner, false);
       if (rootTag != null) {
         for (XmlTag tag : rootTag.getSubTags()) {
           if (Comparing.strEqual(
               StringUtil.unescapeXml(tag.getAttributeValue("name")), externalName)) {
             for (XmlTag annTag : tag.getSubTags()) {
               if (Comparing.strEqual(annTag.getAttributeValue("name"), annotationFQName)) {
                 annTag.delete();
                 break;
               }
             }
             tag.add(
                 XmlElementFactory.getInstance(myPsiManager.getProject())
                     .createTagFromText(createAnnotationTag(annotationFQName, values)));
             return;
           }
         }
         @NonNls String text = "<item name=\'" + StringUtil.escapeXml(externalName) + "\'>\n";
         text += createAnnotationTag(annotationFQName, values);
         text += "</item>";
         rootTag.add(
             XmlElementFactory.getInstance(myPsiManager.getProject()).createTagFromText(text));
       }
     }
   } catch (IncorrectOperationException e) {
     LOG.error(e);
   } finally {
     dropCache();
     if (codeUsageFile.getVirtualFile().isInLocalFileSystem()) {
       UndoUtil.markPsiFileForUndo(codeUsageFile);
     }
   }
 }
 public static void acceptAvailableChildren(
     final DomElement element, final DomElementVisitor visitor) {
   final XmlTag tag = element.getXmlTag();
   if (tag != null) {
     for (XmlTag xmlTag : tag.getSubTags()) {
       final DomElement childElement = element.getManager().getDomElement(xmlTag);
       if (childElement != null) {
         childElement.accept(visitor);
       }
     }
   }
 }
 private static void replaceElements(XmlTag tag, TemplateBuilder builder) {
   for (XmlAttribute attribute : tag.getAttributes()) {
     XmlAttributeValue value = attribute.getValueElement();
     if (value != null) {
       builder.replaceElement(value, TextRange.from(1, 0), new MacroCallNode(new CompleteMacro()));
     }
   }
   if ("<".equals(tag.getText())) {
     builder.replaceElement(
         tag, TextRange.from(1, 0), new MacroCallNode(new CompleteSmartMacro()));
   } else if (tag.getSubTags().length == 0) {
     int i = tag.getText().indexOf("></");
     if (i > 0) {
       builder.replaceElement(
           tag, TextRange.from(i + 1, 0), new MacroCallNode(new CompleteMacro()));
     }
   }
   for (XmlTag subTag : tag.getSubTags()) {
     replaceElements(subTag, builder);
   }
 }
  @Nullable
  public static XmlTag findProperty(
      @NotNull MavenDomProperties mavenDomProperties, @NotNull String propertyName) {
    XmlTag propertiesTag = mavenDomProperties.getXmlTag();
    if (propertiesTag == null) return null;

    for (XmlTag each : propertiesTag.getSubTags()) {
      if (each.getName().equals(propertyName)) {
        return each;
      }
    }

    return null;
  }
  private static void collectDependencies(
      @Nullable XmlTag myTag, @NotNull XmlFile myFile, @NotNull Set<PsiFile> visited) {
    if (visited.contains(myFile)) return;
    visited.add(myFile);

    if (myTag == null) return;
    XmlTag[] tags = myTag.getSubTags();

    for (final XmlTag tag : tags) {
      if (equalsToSchemaName(tag, INCLUDE_TAG_NAME) || equalsToSchemaName(tag, IMPORT_TAG_NAME)) {
        final XmlAttribute schemaLocation = tag.getAttribute("schemaLocation", null);
        if (schemaLocation != null) {
          final XmlFile xmlFile =
              XmlUtil.findNamespaceByLocation(myFile, schemaLocation.getValue());
          addDependency(xmlFile, visited);
        }
      } else if (equalsToSchemaName(tag, REDEFINE_TAG_NAME)) {
        myRedefinedDescriptorsInProcessing.set(visited);
        try {
          final XmlFile file = getRedefinedElementDescriptorFile(tag);
          addDependency(file, visited);
        } finally {
          myRedefinedDescriptorsInProcessing.set(null);
        }
      }
    }

    final String schemaLocationDeclaration =
        myTag.getAttributeValue("schemaLocation", XmlUtil.XML_SCHEMA_INSTANCE_URI);
    if (schemaLocationDeclaration != null) {
      final StringTokenizer tokenizer = new StringTokenizer(schemaLocationDeclaration);

      while (tokenizer.hasMoreTokens()) {
        final String uri = tokenizer.nextToken();

        if (tokenizer.hasMoreTokens()) {
          PsiFile resourceLocation =
              ExternalResourceManager.getInstance()
                  .getResourceLocation(tokenizer.nextToken(), myFile, null);
          if (resourceLocation == null && uri != null)
            resourceLocation =
                ExternalResourceManager.getInstance().getResourceLocation(uri, myFile, null);

          if (resourceLocation instanceof XmlFile)
            addDependency((XmlFile) resourceLocation, visited);
        }
      }
    }
  }
  private static boolean processTagsInNamespaceInner(
      @NotNull final XmlTag rootTag,
      final String[] tagNames,
      final PsiElementProcessor<XmlTag> processor,
      Set<XmlTag> visitedTags) {
    if (visitedTags == null) visitedTags = new HashSet<XmlTag>(3);
    else if (visitedTags.contains(rootTag)) return true;

    visitedTags.add(rootTag);
    XmlTag[] tags = rootTag.getSubTags();

    NextTag:
    for (XmlTag tag : tags) {
      for (String tagName : tagNames) {
        if (equalsToSchemaName(tag, tagName)) {
          final String name = tag.getAttributeValue("name");

          if (name != null) {
            if (!processor.execute(tag)) {
              return false;
            }
          }

          continue NextTag;
        }
      }

      if (equalsToSchemaName(tag, INCLUDE_TAG_NAME)) {
        final String schemaLocation = tag.getAttributeValue("schemaLocation");

        if (schemaLocation != null) {
          final XmlFile xmlFile =
              XmlUtil.findNamespaceByLocation(rootTag.getContainingFile(), schemaLocation);

          if (xmlFile != null) {
            final XmlDocument includedDocument = xmlFile.getDocument();

            if (includedDocument != null) {
              if (!processTagsInNamespaceInner(
                  includedDocument.getRootTag(), tagNames, processor, visitedTags)) return false;
            }
          }
        }
      }
    }

    return true;
  }
  public static Set<XmlTag> collectProperties(
      @NotNull MavenDomProjectModel projectDom, @NotNull final Project project) {
    final Set<XmlTag> properties = new HashSet<XmlTag>();

    Processor<MavenDomProperties> collectProcessor =
        mavenDomProperties -> {
          XmlTag propertiesTag = mavenDomProperties.getXmlTag();
          if (propertiesTag != null) {
            ContainerUtil.addAll(properties, propertiesTag.getSubTags());
          }
          return false;
        };

    processProperties(projectDom, collectProcessor, project);

    return properties;
  }
  private static void inlineMultiTags(
      XmlTag includeTag, XmlTag includeTagParent, XmlTag mergeTag, Project project)
      throws AndroidRefactoringErrorException {
    final Map<String, String> namespacesFromParent =
        includeTagParent.getLocalNamespaceDeclarations();
    final Map<String, String> namespacesToAddToParent = new HashMap<String, String>();
    final Map<String, String> namespacesToAddToEachTag = new HashMap<String, String>();

    for (Map.Entry<String, String> entry : mergeTag.getLocalNamespaceDeclarations().entrySet()) {
      final String prefix = entry.getKey();
      final String namespace = entry.getValue();
      final String declaredNamespace = namespacesFromParent.get(prefix);

      if (declaredNamespace != null && !declaredNamespace.equals(namespace)) {
        namespacesToAddToEachTag.put(prefix, namespace);
      } else {
        namespacesToAddToParent.put(prefix, namespace);
      }
    }
    final XmlTag mergeTagCopy = (XmlTag) mergeTag.copy();
    final XmlElementFactory xmlElementFactory = XmlElementFactory.getInstance(project);

    for (XmlTag subtag : mergeTagCopy.getSubTags()) {
      final XmlAttribute[] attributes = subtag.getAttributes();
      final XmlAttribute firstAttribute = attributes.length > 0 ? attributes[0] : null;

      for (Map.Entry<String, String> entry : namespacesToAddToEachTag.entrySet()) {
        final String prefix = entry.getKey();
        final String namespace = entry.getValue();

        if (!subtag.getLocalNamespaceDeclarations().containsKey(prefix)) {
          final XmlAttribute xmlnsAttr =
              xmlElementFactory.createXmlAttribute("xmlns:" + prefix, namespace);

          if (firstAttribute != null) {
            subtag.addBefore(xmlnsAttr, firstAttribute);
          } else {
            subtag.add(xmlnsAttr);
          }
        }
      }
    }
    replaceByTagContent(project, includeTag, mergeTagCopy);
    addNamespaceAttributes(includeTagParent, namespacesToAddToParent, project);
  }
  @Nullable
  protected TypeDescriptor findTypeDescriptorImpl(
      XmlTag rootTag, final String name, String namespace, Set<XmlTag> visited) {
    XmlNSDescriptorImpl responsibleDescriptor = this;
    if (namespace != null && namespace.length() != 0 && !namespace.equals(getDefaultNamespace())) {
      final XmlNSDescriptor nsDescriptor = rootTag.getNSDescriptor(namespace, true);

      if (nsDescriptor instanceof XmlNSDescriptorImpl) {
        responsibleDescriptor = (XmlNSDescriptorImpl) nsDescriptor;
      }
    }

    if (responsibleDescriptor != this) {
      return responsibleDescriptor.findTypeDescriptor(XmlUtil.findLocalNameByQualifiedName(name));
    }

    if (rootTag == null) return null;
    if (visited != null) {
      if (visited.contains(rootTag)) return null;
      visited.add(rootTag);
    }

    final Pair<QNameKey, XmlTag> pair =
        new Pair<QNameKey, XmlTag>(new QNameKey(name, namespace), rootTag);

    final CachedValue<TypeDescriptor> descriptor = myTypesMap.get(pair);
    if (descriptor != null) {
      TypeDescriptor value = descriptor.getValue();
      if (value == null
          || (value instanceof ComplexTypeDescriptor
              && ((ComplexTypeDescriptor) value).getDeclaration().isValid())) return value;
    }

    XmlTag[] tags = rootTag.getSubTags();

    if (visited == null) {
      visited = new HashSet<XmlTag>(1);
      visited.add(rootTag);
    }

    return doFindIn(tags, name, namespace, pair, rootTag, visited);
  }
  private void initSubstitutes() {
    if (mySubstitutions == null) {
      mySubstitutions = new HashMap<String, List<XmlTag>>();

      XmlTag[] tags = myTag.getSubTags();

      for (XmlTag tag : tags) {
        if (equalsToSchemaName(tag, ELEMENT_TAG_NAME)) {
          final String substAttr = tag.getAttributeValue("substitutionGroup");
          if (substAttr != null) {
            String substLocalName = XmlUtil.findLocalNameByQualifiedName(substAttr);
            List<XmlTag> list = mySubstitutions.get(substLocalName);
            if (list == null) {
              list = new LinkedList<XmlTag>();
              mySubstitutions.put(substLocalName, list);
            }
            list.add(tag);
          }
        }
      }
    }
  }
 @Nullable
 private static XmlTag getAnchor(
     @NotNull XmlTag contextTag, Editor editor, XmlElementDescriptor selected) {
   XmlContentDFA contentDFA = XmlContentDFA.getContentDFA(contextTag);
   int offset = editor.getCaretModel().getOffset();
   if (contentDFA == null) {
     return null;
   }
   XmlTag anchor = null;
   boolean previousPositionIsPossible = true;
   for (XmlTag subTag : contextTag.getSubTags()) {
     if (contentDFA.getPossibleElements().contains(selected)) {
       if (subTag.getTextOffset() > offset) {
         break;
       }
       anchor = subTag;
       previousPositionIsPossible = true;
     } else {
       previousPositionIsPossible = false;
     }
     contentDFA.transition(subTag);
   }
   return previousPositionIsPossible ? null : anchor;
 }
  private TypeDescriptor doFindIn(
      final XmlTag[] tags,
      final String name,
      final String namespace,
      final Pair<QNameKey, XmlTag> pair,
      final XmlTag rootTag,
      final Set<XmlTag> visited) {
    for (final XmlTag tag : tags) {
      if (equalsToSchemaName(tag, "complexType")) {
        if (name == null) {
          CachedValue<TypeDescriptor> value = createAndPutTypesCachedValue(tag, pair);
          return value.getValue();
        }

        String nameAttribute = tag.getAttributeValue("name");

        if (isSameName(name, namespace, nameAttribute)) {
          CachedValue<TypeDescriptor> cachedValue = createAndPutTypesCachedValue(tag, pair);
          return cachedValue.getValue();
        }
      } else if (equalsToSchemaName(tag, "simpleType")) {

        if (name == null) {
          CachedValue<TypeDescriptor> value = createAndPutTypesCachedValueSimpleType(tag, pair);
          return value.getValue();
        }

        String nameAttribute = tag.getAttributeValue("name");

        if (isSameName(name, namespace, nameAttribute)) {
          CachedValue<TypeDescriptor> cachedValue = createAndPutTypesCachedValue(tag, pair);
          return cachedValue.getValue();
        }
      } else if (equalsToSchemaName(tag, INCLUDE_TAG_NAME)
          || (equalsToSchemaName(tag, IMPORT_TAG_NAME)
              && (namespace == null || !namespace.equals(getDefaultNamespace())))) {
        final String schemaLocation = tag.getAttributeValue("schemaLocation");
        if (schemaLocation != null) {
          final XmlFile xmlFile =
              XmlUtil.findNamespaceByLocation(rootTag.getContainingFile(), schemaLocation);

          if (xmlFile != null) {
            final XmlDocument document = xmlFile.getDocument();

            if (document != null) {

              final CachedValue<TypeDescriptor> value =
                  CachedValuesManager.getManager(tag.getProject())
                      .createCachedValue(
                          new CachedValueProvider<TypeDescriptor>() {
                            public Result<TypeDescriptor> compute() {
                              final String currentName = tag.getAttributeValue("name");

                              if ((currentName != null
                                      && !currentName.equals(
                                          XmlUtil.findLocalNameByQualifiedName(name)))
                                  || !xmlFile.isValid()
                                  || xmlFile.getDocument() == null) {
                                myTypesMap.remove(pair);
                                return new Result<TypeDescriptor>(null);
                              }

                              final XmlDocument document = xmlFile.getDocument();
                              final XmlNSDescriptorImpl nsDescriptor =
                                  findNSDescriptor(tag, document);

                              if (nsDescriptor == null) {
                                myTypesMap.remove(pair);
                                return new Result<TypeDescriptor>(null);
                              }

                              final XmlTag rTag = document.getRootTag();

                              final TypeDescriptor complexTypeDescriptor =
                                  nsDescriptor.findTypeDescriptorImpl(
                                      rTag, name, namespace, visited);
                              return new Result<TypeDescriptor>(complexTypeDescriptor, rTag);
                            }
                          },
                          false);

              if (value.getValue() != null) {
                myTypesMap.put(pair, value);
                return value.getValue();
              }
            }
          }
        }
      } else if (equalsToSchemaName(tag, REDEFINE_TAG_NAME)) {
        final XmlTag[] subTags = tag.getSubTags();
        TypeDescriptor descriptor = doFindIn(subTags, name, namespace, pair, rootTag, visited);
        if (descriptor != null) return descriptor;

        final XmlNSDescriptorImpl nsDescriptor = getRedefinedElementDescriptor(tag);
        if (nsDescriptor != null) {
          final XmlTag redefinedRootTag =
              ((XmlDocument) nsDescriptor.getDeclaration()).getRootTag();
          descriptor =
              doFindIn(
                  redefinedRootTag.getSubTags(), name, namespace, pair, redefinedRootTag, visited);
          if (descriptor != null) return descriptor;
        }
      }
    }
    return null;
  }
 private boolean processExistingExternalAnnotations(
     @NotNull final PsiModifierListOwner listOwner,
     @NotNull final String annotationFQN,
     @NotNull final Processor<XmlTag> annotationTagProcessor) {
   try {
     final List<XmlFile> files = findExternalAnnotationsXmlFiles(listOwner);
     if (files == null) {
       notifyAfterAnnotationChanging(listOwner, annotationFQN, false);
       return false;
     }
     boolean processedAnything = false;
     for (final XmlFile file : files) {
       if (!file.isValid()) {
         continue;
       }
       if (ReadonlyStatusHandler.getInstance(myPsiManager.getProject())
           .ensureFilesWritable(file.getVirtualFile())
           .hasReadonlyFiles()) {
         continue;
       }
       final XmlDocument document = file.getDocument();
       if (document == null) {
         continue;
       }
       final XmlTag rootTag = document.getRootTag();
       if (rootTag == null) {
         continue;
       }
       final String externalName = getExternalName(listOwner, false);
       final String oldExternalName = getNormalizedExternalName(listOwner);
       for (final XmlTag tag : rootTag.getSubTags()) {
         final String className = StringUtil.unescapeXml(tag.getAttributeValue("name"));
         if (!Comparing.strEqual(className, externalName)
             && !Comparing.strEqual(className, oldExternalName)) {
           continue;
         }
         for (final XmlTag annotationTag : tag.getSubTags()) {
           if (!Comparing.strEqual(annotationTag.getAttributeValue("name"), annotationFQN)) {
             continue;
           }
           CommandProcessor.getInstance()
               .executeCommand(
                   myPsiManager.getProject(),
                   new Runnable() {
                     @Override
                     public void run() {
                       try {
                         annotationTagProcessor.process(annotationTag);
                         commitChanges(file);
                       } catch (IncorrectOperationException e) {
                         LOG.error(e);
                       }
                     }
                   },
                   ExternalAnnotationsManagerImpl.class.getName(),
                   null);
           processedAnything = true;
         }
       }
     }
     notifyAfterAnnotationChanging(listOwner, annotationFQN, processedAnything);
     return processedAnything;
   } finally {
     dropCache();
   }
 }
  public boolean checkAvailable(
      @NotNull final Editor editor,
      @NotNull final PsiFile file,
      @NotNull final MoveInfo info,
      final boolean down) {
    if (!(file instanceof XmlFile)) {
      return false;
    }
    boolean available = super.checkAvailable(editor, file, info, down);
    if (!available) return false;

    // updated moved range end to cover multiline tag start
    final Document document = editor.getDocument();
    int movedLineStart = document.getLineStartOffset(info.toMove.startLine);
    final int movedLineEnd = document.getLineEndOffset(info.toMove.endLine - 1);

    PsiElement movedEndElement = file.findElementAt(movedLineEnd);
    if (movedEndElement instanceof PsiWhiteSpace)
      movedEndElement = PsiTreeUtil.prevLeaf(movedEndElement);
    PsiElement movedStartElement = file.findElementAt(movedLineStart);
    if (movedStartElement instanceof PsiWhiteSpace)
      movedStartElement = PsiTreeUtil.nextLeaf(movedStartElement);

    if (movedEndElement == null || movedStartElement == null) return false;
    final PsiNamedElement namedParentAtEnd =
        PsiTreeUtil.getParentOfType(movedEndElement, PsiNamedElement.class);
    final PsiNamedElement namedParentAtStart =
        PsiTreeUtil.getParentOfType(movedStartElement, PsiNamedElement.class);

    final XmlText text = PsiTreeUtil.getParentOfType(movedStartElement, XmlText.class);
    final XmlText text2 = PsiTreeUtil.getParentOfType(movedEndElement, XmlText.class);

    // Let's do not care about injections for this mover
    if ((text != null && InjectedLanguageUtil.getInjectedPsiFiles(text) != null)
        || (text2 != null && InjectedLanguageUtil.getInjectedPsiFiles(text2) != null)) {
      return false;
    }

    XmlTag nearestTag = PsiTreeUtil.getParentOfType(movedStartElement, XmlTag.class);
    if (nearestTag != null
        && ("script".equals(nearestTag.getLocalName())
            || (nearestTag instanceof HtmlTag
                && "script".equalsIgnoreCase(nearestTag.getLocalName())))) {
      return false;
    }

    PsiNamedElement movedParent = null;

    if (namedParentAtEnd == namedParentAtStart) movedParent = namedParentAtEnd;
    else if (namedParentAtEnd instanceof XmlAttribute
        && namedParentAtStart instanceof XmlTag
        && namedParentAtEnd.getParent() == namedParentAtStart) {
      movedParent = namedParentAtStart;
    } else if (namedParentAtStart instanceof XmlAttribute
        && namedParentAtEnd instanceof XmlTag
        && namedParentAtStart.getParent() == namedParentAtEnd) {
      movedParent = namedParentAtEnd;
    }

    if (movedParent == null) {
      return false;
    }

    final TextRange textRange = movedParent.getTextRange();

    if (movedParent instanceof XmlTag) {
      final XmlTag tag = (XmlTag) movedParent;
      final TextRange valueRange = tag.getValue().getTextRange();
      final int valueStart = valueRange.getStartOffset();

      if (movedLineStart < valueStart && valueStart + 1 < document.getTextLength()) {
        movedLineStart = updateMovedRegionEnd(document, movedLineStart, valueStart + 1, info, down);
      }
      if (movedLineStart < valueStart) {
        movedLineStart =
            updatedMovedRegionStart(
                document, movedLineStart, tag.getTextRange().getStartOffset(), info, down);
      }
    } else if (movedParent instanceof XmlAttribute) {
      final int endOffset = textRange.getEndOffset() + 1;
      if (endOffset < document.getTextLength())
        movedLineStart = updateMovedRegionEnd(document, movedLineStart, endOffset, info, down);
      movedLineStart =
          updatedMovedRegionStart(document, movedLineStart, textRange.getStartOffset(), info, down);
    }

    final TextRange moveDestinationRange =
        new TextRange(
            document.getLineStartOffset(info.toMove2.startLine),
            document.getLineStartOffset(info.toMove2.endLine));

    if (movedParent instanceof XmlAttribute) {
      final XmlTag parent = ((XmlAttribute) movedParent).getParent();

      if (parent != null) {
        final TextRange valueRange = parent.getValue().getTextRange();

        // Do not move attributes out of tags
        if ((down && moveDestinationRange.getEndOffset() >= valueRange.getStartOffset())
            || (!down
                && moveDestinationRange.getStartOffset()
                    <= parent.getTextRange().getStartOffset())) {
          info.toMove2 = null;
        }
      }
    }

    if (down) {
      PsiElement updatedElement = file.findElementAt(moveDestinationRange.getEndOffset());
      if (updatedElement instanceof PsiWhiteSpace)
        updatedElement = PsiTreeUtil.prevLeaf(updatedElement);

      if (updatedElement != null) {
        final PsiNamedElement namedParent =
            PsiTreeUtil.getParentOfType(updatedElement, movedParent.getClass());

        if (namedParent instanceof XmlTag) {
          final XmlTag tag = (XmlTag) namedParent;
          final int offset =
              tag.isEmpty()
                  ? tag.getTextRange().getStartOffset()
                  : tag.getValue().getTextRange().getStartOffset();
          updatedMovedIntoEnd(document, info, offset);
        } else if (namedParent instanceof XmlAttribute) {
          updatedMovedIntoEnd(document, info, namedParent.getTextRange().getEndOffset());
        }
      }
    } else {
      PsiElement updatedElement = file.findElementAt(moveDestinationRange.getStartOffset());
      if (updatedElement instanceof PsiWhiteSpace)
        updatedElement = PsiTreeUtil.nextLeaf(updatedElement);

      if (updatedElement != null) {
        final PsiNamedElement namedParent =
            PsiTreeUtil.getParentOfType(updatedElement, movedParent.getClass());

        if (namedParent instanceof XmlTag) {
          final XmlTag tag = (XmlTag) namedParent;
          final TextRange tagValueRange = tag.getValue().getTextRange();

          // We need to update destination range to jump over tag start
          final XmlTag[] subtags = tag.getSubTags();
          if ((tagValueRange.contains(movedLineStart)
                  && subtags.length > 0
                  && subtags[0] == movedParent)
              || (tagValueRange.getLength() == 0
                  && tag.getTextRange().intersects(moveDestinationRange))) {
            final int line = document.getLineNumber(tag.getTextRange().getStartOffset());
            final LineRange toMove2 = info.toMove2;
            info.toMove2 = new LineRange(Math.min(line, toMove2.startLine), toMove2.endLine);
          }
        } else if (namedParent instanceof XmlAttribute) {
          final int line = document.getLineNumber(namedParent.getTextRange().getStartOffset());
          final LineRange toMove2 = info.toMove2;
          info.toMove2 = new LineRange(Math.min(line, toMove2.startLine), toMove2.endLine);
        }
      }
    }

    return true;
  }
  @Nullable
  public XmlElementDescriptor getElementDescriptor(
      String localName, String namespace, Set<XmlNSDescriptorImpl> visited, boolean reference) {
    if (visited.contains(this)) return null;

    final QNameKey pair = new QNameKey(namespace, localName);
    final CachedValue<XmlElementDescriptor> descriptor = myDescriptorsMap.get(pair);
    if (descriptor != null) {
      final XmlElementDescriptor value = descriptor.getValue();
      if (value == null || value.getDeclaration().isValid()) return value;
    }

    final XmlTag rootTag = myTag;
    if (rootTag == null) return null;
    XmlTag[] tags = rootTag.getSubTags();
    visited.add(this);

    for (final XmlTag tag : tags) {
      if (equalsToSchemaName(tag, ELEMENT_TAG_NAME)) {
        String name = tag.getAttributeValue("name");

        if (name != null) {
          if (checkElementNameEquivalence(localName, namespace, name, tag)) {
            final CachedValue<XmlElementDescriptor> cachedValue =
                CachedValuesManager.getManager(tag.getProject())
                    .createCachedValue(
                        new CachedValueProvider<XmlElementDescriptor>() {
                          public Result<XmlElementDescriptor> compute() {
                            final String name = tag.getAttributeValue("name");

                            if (name != null && !name.equals(pair.second)) {
                              myDescriptorsMap.remove(pair);
                              return new Result<XmlElementDescriptor>(null);
                            }
                            final XmlElementDescriptor xmlElementDescriptor =
                                createElementDescriptor(tag);
                            return new Result<XmlElementDescriptor>(
                                xmlElementDescriptor, xmlElementDescriptor.getDependences());
                          }
                        },
                        false);
            myDescriptorsMap.put(pair, cachedValue);
            return cachedValue.getValue();
          }
        }
      } else if (equalsToSchemaName(tag, INCLUDE_TAG_NAME)
          || (reference
              && equalsToSchemaName(tag, IMPORT_TAG_NAME)
              && (namespace.equals(tag.getAttributeValue("namespace"))
                  || namespace.length() == 0 && tag.getAttributeValue("namespace") == null))) {
        final XmlAttribute schemaLocation = tag.getAttribute("schemaLocation", null);
        if (schemaLocation != null) {
          final XmlFile xmlFile =
              XmlUtil.findNamespaceByLocation(
                  rootTag.getContainingFile(), schemaLocation.getValue());
          if (xmlFile != null) {
            final XmlDocument includedDocument = xmlFile.getDocument();
            if (includedDocument != null) {
              final PsiMetaData data = includedDocument.getMetaData();
              if (data instanceof XmlNSDescriptorImpl) {
                final XmlElementDescriptor elementDescriptor =
                    ((XmlNSDescriptorImpl) data)
                        .getElementDescriptor(localName, namespace, visited, reference);
                if (elementDescriptor != null) {
                  // final CachedValue<XmlElementDescriptor> value =
                  // includedDocument.getManager().getCachedValuesManager()
                  //  .createCachedValue(new CachedValueProvider<XmlElementDescriptor>() {
                  //    public Result<XmlElementDescriptor> compute() {
                  //      return new Result<XmlElementDescriptor>(elementDescriptor,
                  // elementDescriptor.getDependences());
                  //    }
                  //  }, false);
                  // return value.getValue();
                  return elementDescriptor;
                }
              }
            }
          }
        }
      } else if (equalsToSchemaName(tag, REDEFINE_TAG_NAME)) {
        final XmlNSDescriptorImpl nsDescriptor = getRedefinedElementDescriptor(tag);
        if (nsDescriptor != null) {
          final XmlElementDescriptor xmlElementDescriptor =
              nsDescriptor.getElementDescriptor(localName, namespace, visited, reference);
          if (xmlElementDescriptor != null) return xmlElementDescriptor;
        }
      }
    }

    return null;
  }
  @Nullable
  private XmlAttributeDescriptor getAttributeImpl(
      String localName, String namespace, Set<XmlTag> visited) {
    if (myTag == null) return null;

    XmlNSDescriptorImpl nsDescriptor = (XmlNSDescriptorImpl) myTag.getNSDescriptor(namespace, true);

    if (nsDescriptor != this && nsDescriptor != null) {
      return nsDescriptor.getAttributeImpl(localName, namespace, visited);
    }

    if (visited == null) visited = new HashSet<XmlTag>(1);
    else if (visited.contains(myTag)) return null;
    visited.add(myTag);
    XmlTag[] tags = myTag.getSubTags();

    for (XmlTag tag : tags) {
      if (equalsToSchemaName(tag, ATTRIBUTE_TAG_NAME)) {
        String name = tag.getAttributeValue("name");

        if (name != null) {
          if (checkElementNameEquivalence(localName, namespace, name, tag)) {
            return createAttributeDescriptor(tag);
          }
        }
      } else if (equalsToSchemaName(tag, INCLUDE_TAG_NAME)
          || (equalsToSchemaName(tag, IMPORT_TAG_NAME)
              && namespace.equals(tag.getAttributeValue("namespace")))) {
        final XmlAttribute schemaLocation = tag.getAttribute("schemaLocation", null);

        if (schemaLocation != null) {
          final XmlFile xmlFile =
              XmlUtil.findNamespaceByLocation(myTag.getContainingFile(), schemaLocation.getValue());

          if (xmlFile != null) {

            final XmlDocument includedDocument = xmlFile.getDocument();
            if (includedDocument != null) {
              final PsiMetaData data = includedDocument.getMetaData();

              if (data instanceof XmlNSDescriptorImpl) {
                final XmlAttributeDescriptor attributeDescriptor =
                    ((XmlNSDescriptorImpl) data).getAttributeImpl(localName, namespace, visited);

                if (attributeDescriptor != null) {
                  final CachedValue<XmlAttributeDescriptor> value =
                      CachedValuesManager.getManager(includedDocument.getProject())
                          .createCachedValue(
                              new CachedValueProvider<XmlAttributeDescriptor>() {
                                public Result<XmlAttributeDescriptor> compute() {
                                  return new Result<XmlAttributeDescriptor>(
                                      attributeDescriptor, attributeDescriptor.getDependences());
                                }
                              },
                              false);
                  return value.getValue();
                }
              }
            }
          }
        }
      }
    }

    return null;
  }
  private static XmlTag findSpecialTagIn(
      final XmlTag[] tags,
      final String specialName,
      final String name,
      final XmlTag rootTag,
      final XmlNSDescriptorImpl descriptor,
      final HashSet<XmlTag> visited) {
    for (XmlTag tag : tags) {
      if (equalsToSchemaName(tag, specialName)) {
        String attribute = tag.getAttributeValue("name");

        if (name.equals(attribute)
            || name.indexOf(":") >= 0 && name.substring(name.indexOf(":") + 1).equals(attribute)) {
          return tag;
        }
      } else if (equalsToSchemaName(tag, INCLUDE_TAG_NAME)
          || (equalsToSchemaName(tag, IMPORT_TAG_NAME)
              && rootTag
                  .getNamespaceByPrefix(XmlUtil.findPrefixByQualifiedName(name))
                  .equals(tag.getAttributeValue("namespace")))) {
        final String schemaLocation = tag.getAttributeValue("schemaLocation");

        if (schemaLocation != null) {
          final XmlFile xmlFile =
              XmlUtil.findNamespaceByLocation(rootTag.getContainingFile(), schemaLocation);

          if (xmlFile != null) {
            final XmlDocument document = xmlFile.getDocument();
            if (document != null) {
              final XmlTag rTag =
                  findSpecialTag(name, specialName, document.getRootTag(), descriptor, visited);

              if (rTag != null) return rTag;
            }
          }
        }
      } else if (equalsToSchemaName(tag, REDEFINE_TAG_NAME)) {
        XmlTag rTag =
            findSpecialTagIn(tag.getSubTags(), specialName, name, rootTag, descriptor, visited);
        if (rTag != null) return rTag;

        final XmlNSDescriptorImpl nsDescriptor = getRedefinedElementDescriptor(tag);
        if (nsDescriptor != null) {
          final XmlTag redefinedRootTag =
              ((XmlDocument) nsDescriptor.getDeclaration()).getRootTag();

          rTag =
              findSpecialTagIn(
                  redefinedRootTag.getSubTags(),
                  specialName,
                  name,
                  redefinedRootTag,
                  nsDescriptor,
                  visited);
          if (rTag != null) return rTag;
        }
      }
    }

    return null;
  }