@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 String getDefaultValue() {
    if (isFixed()) {
      return myTag.getAttributeValue("fixed");
    }

    return myTag.getAttributeValue("default");
  }
 @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();
   }
 }
 private static boolean processDevContext(final PsiFile file, Processor<PsiElement> processor) {
   final XmlTag tag = getTagByInjectedFile(file);
   final XmlTag parentTag = tag == null ? null : tag.getParentTag();
   final String parentTagName = parentTag == null ? null : parentTag.getName();
   final String name = tag == null ? null : tag.getName();
   if ("place".equals(name) && "injection".equals(parentTagName)) {
     return processRootsByClassNames(file, parentTag.getAttributeValue("injector-id"), processor);
   } else if ("pattern".equals(name) && parentTag != null) {
     return processRootsByClassNames(file, tag.getAttributeValue("type"), processor);
   }
   return true;
 }
  public String getName(PsiElement context) {

    if (context == null) {
      return getName();
    }
    final String form = myTag.getAttributeValue("form");
    boolean isQualifiedAttr = QUALIFIED_ATTR_VALUE.equals(form);

    final XmlTag rootTag = (((XmlFile) myTag.getContainingFile())).getRootTag();
    assert rootTag != null;
    String targetNs = rootTag.getAttributeValue("targetNamespace");
    XmlTag contextTag = (XmlTag) context;
    String name = getName();

    boolean attributeShouldBeQualified = false;

    String contextNs = contextTag.getNamespace();
    if (targetNs != null && !contextNs.equals(targetNs)) {
      final XmlElementDescriptor xmlElementDescriptor = contextTag.getDescriptor();

      if (xmlElementDescriptor instanceof XmlElementDescriptorImpl) {
        final XmlElementDescriptorImpl elementDescriptor =
            (XmlElementDescriptorImpl) xmlElementDescriptor;
        final TypeDescriptor type = elementDescriptor.getType();

        if (type instanceof ComplexTypeDescriptor) {
          final ComplexTypeDescriptor typeDescriptor = (ComplexTypeDescriptor) type;
          attributeShouldBeQualified =
              typeDescriptor.canContainAttribute(targetNs, null)
                  != ComplexTypeDescriptor.CanContainAttributeType.CanNotContain;
        }

        if (!attributeShouldBeQualified && contextNs.length() == 0 && targetNs.length() > 0) {
          attributeShouldBeQualified = !targetNs.equals(elementDescriptor.getNamespace());
        }
      }
    }

    if (targetNs != null
        && (isQualifiedAttr
            || QUALIFIED_ATTR_VALUE.equals(rootTag.getAttributeValue("attributeFormDefault"))
            || attributeShouldBeQualified)) {
      final String prefixByNamespace = contextTag.getPrefixByNamespace(targetNs);
      if (prefixByNamespace != null && prefixByNamespace.length() > 0) {
        name = prefixByNamespace + ":" + name;
      }
    }

    return name;
  }
  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 String findUrl(PsiFile file, int offset, String uri) {
    final PsiElement currentElement = file.findElementAt(offset);
    final XmlAttribute attribute = PsiTreeUtil.getParentOfType(currentElement, XmlAttribute.class);

    if (attribute != null) {
      final XmlTag tag = PsiTreeUtil.getParentOfType(currentElement, XmlTag.class);

      if (tag != null) {
        final String prefix = tag.getPrefixByNamespace(XmlUtil.XML_SCHEMA_INSTANCE_URI);
        if (prefix != null) {
          final String attrValue =
              tag.getAttributeValue(XmlUtil.SCHEMA_LOCATION_ATT, XmlUtil.XML_SCHEMA_INSTANCE_URI);
          if (attrValue != null) {
            final StringTokenizer tokenizer = new StringTokenizer(attrValue);

            while (tokenizer.hasMoreElements()) {
              if (uri.equals(tokenizer.nextToken())) {
                if (!tokenizer.hasMoreElements()) return uri;
                final String url = tokenizer.nextToken();

                return url.startsWith(HTTP_PROTOCOL) ? url : uri;
              }

              if (!tokenizer.hasMoreElements()) return uri;
              tokenizer.nextToken(); // skip file location
            }
          }
        }
      }
    }
    return uri;
  }
  protected void setValue(@Nullable final String value) {
    final XmlTag tag = ensureTagExists();
    final String attributeName = getXmlElementName();
    final String namespace = getXmlApiCompatibleNamespace(getParentHandler());
    final String oldValue = StringUtil.unescapeXml(tag.getAttributeValue(attributeName, namespace));
    final String newValue = XmlStringUtil.escapeString(value);
    if (Comparing.equal(oldValue, newValue, true)) return;

    getManager()
        .runChange(
            new Runnable() {
              public void run() {
                try {
                  XmlAttribute attribute = tag.setAttribute(attributeName, namespace, newValue);
                  setXmlElement(attribute);
                  getManager()
                      .cacheHandler(
                          DomManagerImpl.DOM_ATTRIBUTE_HANDLER_KEY,
                          attribute,
                          AttributeChildInvocationHandler.this);
                } catch (IncorrectOperationException e) {
                  LOG.error(e);
                }
              }
            });
    final DomElement proxy = getProxy();
    final DomElement element = proxy;
    getManager()
        .fireEvent(oldValue != null ? new DomEvent(proxy, false) : new DomEvent(element, true));
  }
  public void init(PsiElement element) {
    myFile = (XmlFile) element.getContainingFile();

    if (element instanceof XmlTag) {
      myTag = (XmlTag) element;
    } else {
      final XmlDocument document = myFile.getDocument();

      if (document != null) {
        myTag = document.getRootTag();
      }
    }

    if (myTag != null) {
      myTargetNamespace = myTag.getAttributeValue("targetNamespace");
    }

    final THashSet<PsiFile> dependenciesSet = new THashSet<PsiFile>();
    final Set<PsiFile> redefineProcessingSet = myRedefinedDescriptorsInProcessing.get();
    if (redefineProcessingSet != null) {
      dependenciesSet.addAll(redefineProcessingSet);
    }
    collectDependencies(myTag, myFile, dependenciesSet);
    dependencies = ArrayUtil.toObjectArray(dependenciesSet);
  }
 @NotNull
 @Override
 public String filterText(@NotNull String text, @NotNull TemplateToken token) {
   XmlDocument document = token.getFile().getDocument();
   if (document != null) {
     XmlTag tag = document.getRootTag();
     if (tag != null) {
       String classAttr = tag.getAttributeValue(HtmlUtil.CLASS_ATTRIBUTE_NAME);
       String idAttr = tag.getAttributeValue(HtmlUtil.ID_ATTRIBUTE_NAME);
       if (!isNullOrEmpty(classAttr) || !isNullOrEmpty(idAttr)) {
         String commentString = buildCommentString(classAttr, idAttr);
         return text + "\n<!-- /" + commentString + " -->";
       }
     }
   }
   return text;
 }
  public TypeDescriptor getTypeDescriptor(XmlTag descriptorTag) {
    String type = descriptorTag.getAttributeValue("type");

    if (type != null) {
      return getTypeDescriptor(type, descriptorTag);
    }

    return findTypeDescriptorImpl(descriptorTag, null, null, null);
  }
 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);
     }
   }
 }
  @NotNull
  public PsiReference[] getReferencesByElement(
      @NotNull PsiElement element, @NotNull final ProcessingContext context) {
    boolean soft = myDefaultSoft;

    if (element instanceof XmlAttributeValue) {
      final XmlAttribute xmlAttribute = (XmlAttribute) element.getParent();
      if (element.getTextLength() < 2) {
        return PsiReference.EMPTY_ARRAY;
      }

      final XmlTag tag = xmlAttribute.getParent();
      String value = null;
      String bundle = tag.getAttributeValue("bundle");
      if ("key".equals(xmlAttribute.getName())) {
        value = xmlAttribute.getValue();
      } else if ("groupKey".equals(xmlAttribute.getName())) {
        value = xmlAttribute.getValue();
        final String groupBundle = tag.getAttributeValue("groupBundle");
        if (groupBundle != null) {
          bundle = groupBundle;
        }
      }
      if (value != null) {
        return new PsiReference[] {
          new PropertyReference(value, xmlAttribute.getValueElement(), bundle, soft) {
            @Override
            protected List<PropertiesFile> retrievePropertyFilesByBundleName(
                String bundleName, PsiElement element) {
              final Project project = element.getProject();
              return PropertiesReferenceManager.getInstance(project)
                  .findPropertiesFiles(
                      GlobalSearchScope.projectScope(project),
                      bundleName,
                      BundleNameEvaluator.DEFAULT);
            }
          }
        };
      }
    }
    return PsiReference.EMPTY_ARRAY;
  }
  private static EnumerationData getEnumeratedValuesImpl(final XmlTag declaration) {
    if ("boolean".equals(declaration.getAttributeValue("name"))) {
      return new EnumerationData(new String[] {"true", "false"}, true);
    }

    final HashSet<String> variants = new HashSet<String>();
    final boolean exaustive = XmlUtil.collectEnumerationValues(declaration, variants);

    if (variants.size() > 0) {
      return new EnumerationData(ArrayUtil.toStringArray(variants), exaustive);
    }
    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);
        }
      }
    }
  }
  public XmlElementDescriptor[] getSubstitutes(String localName, String namespace) {
    List<XmlElementDescriptor> result = new ArrayList<XmlElementDescriptor>();

    initSubstitutes();

    List<XmlTag> substitutions = mySubstitutions.get(localName);
    if (substitutions == null) return XmlElementDescriptor.EMPTY_ARRAY;
    for (XmlTag tag : substitutions) {
      final String substAttr = tag.getAttributeValue("substitutionGroup");
      if (substAttr != null && checkElementNameEquivalence(localName, namespace, substAttr, tag)) {
        result.add(createElementDescriptor(tag));
      }
    }

    return result.toArray(new XmlElementDescriptor[result.size()]);
  }
  public boolean isAvailable(@Nullable XmlTag tag, PsiFile file) {
    if (file instanceof XmlFile && file.isValid() && AndroidFacet.getInstance(file) != null) {
      ResourceFolderType folderType = ResourceHelper.getFolderType(file);
      if (folderType == null) {
        return false;
      } else if (folderType != ResourceFolderType.VALUES) {
        return true;
      } else {
        // In value files, you can invoke this action if the caret is on or inside an element (other
        // than the
        // root <resources> tag). Only accept the element if it has a known type with a known name.
        if (tag != null && tag.getAttributeValue(ATTR_NAME) != null) {
          return AndroidResourceUtil.getResourceForResourceTag(tag) != null;
        }
      }
    }

    return false;
  }
  public static XmlFile getRedefinedElementDescriptorFile(final XmlTag parentTag) {
    final String schemaL = parentTag.getAttributeValue(XmlUtil.SCHEMA_LOCATION_ATT);

    if (schemaL != null) {
      final PsiReference[] references =
          parentTag
              .getAttribute(XmlUtil.SCHEMA_LOCATION_ATT, null)
              .getValueElement()
              .getReferences();

      if (references.length > 0) {
        final PsiElement psiElement = references[references.length - 1].resolve();

        if (psiElement instanceof XmlFile) {
          return ((XmlFile) psiElement);
        }
      }
    }
    return null;
  }
  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);
          }
        }
      }
    }
  }
  public static boolean isSettingsFile(PsiFile file) {
    if (!(file instanceof XmlFile)) return false;

    XmlTag rootTag = ((XmlFile) file).getRootTag();
    if (rootTag == null || !"settings".equals(rootTag.getName())) return false;

    String xmlns = rootTag.getAttributeValue("xmlns");
    if (xmlns != null) {
      return xmlns.contains("maven");
    }

    boolean hasTag = false;

    for (PsiElement e = rootTag.getFirstChild(); e != null; e = e.getNextSibling()) {
      if (e instanceof XmlTag) {
        if (SUBTAGS_IN_SETTINGS_FILE.contains(((XmlTag) e).getName())) return true;
        hasTag = true;
      }
    }

    return !hasTag;
  }
  protected static void forkResourceValue(
      @NotNull Project project,
      @NotNull XmlTag tag,
      @NotNull PsiFile file,
      @NotNull AndroidFacet facet,
      @Nullable PsiDirectory dir) {

    PsiDirectory resFolder = findRes(file);
    if (resFolder == null) {
      return; // shouldn't happen; we checked in isAvailable
    }
    String name = tag.getAttributeValue(ATTR_NAME);
    ResourceType type = AndroidResourceUtil.getResourceForResourceTag(tag);
    if (name == null || type == null) {
      return; // shouldn't happen; we checked in isAvailable
    }
    if (dir == null) {
      dir = selectFolderDir(project, resFolder.getVirtualFile(), ResourceFolderType.VALUES);
    }
    if (dir != null) {
      String value = PsiResourceItem.getTextContent(tag).trim();
      createValueResource(file, facet, dir, name, value, type, tag.getText());
    }
  }
  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;
  }
 public void init(PsiElement element) {
   myTag = (XmlTag) element;
   myUse = myTag.getAttributeValue("use");
 }
 public boolean isFixed() {
   return myTag.getAttributeValue("fixed") != null;
 }
 @Nullable
 public String getType() {
   return myTag.getAttributeValue("type");
 }
 public boolean execute(final XmlTag element) {
   result.add(getElementDescriptor(element.getAttributeValue("name"), getDefaultNamespace()));
   return true;
 }
  @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;
  }
  @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;
  }
 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();
   }
 }
  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;
  }