All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.intellij.xml.impl.dtd.XmlElementDescriptorImpl Maven / Gradle / Ivy

Go to download

A packaging of the IntelliJ Community Edition xml-psi-impl library. This is release number 1 of trunk branch 142.

The newest version!
/*
 * Copyright 2000-2014 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.intellij.xml.impl.dtd;

import com.intellij.javaee.ExternalResourceManager;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.UserDataCache;
import com.intellij.psi.PsiElement;
import com.intellij.psi.filters.ClassFilter;
import com.intellij.psi.meta.PsiMetaData;
import com.intellij.psi.meta.PsiWritableMetaData;
import com.intellij.psi.scope.processor.FilterElementProcessor;
import com.intellij.psi.search.PsiElementProcessor;
import com.intellij.psi.util.CachedValue;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.xml.*;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.xml.XmlAttributeDescriptor;
import com.intellij.xml.XmlElementDescriptor;
import com.intellij.xml.XmlElementsGroup;
import com.intellij.xml.XmlNSDescriptor;
import com.intellij.xml.util.XmlNSDescriptorSequence;
import com.intellij.xml.util.XmlUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;

/**
 * @author Mike
 */
public class XmlElementDescriptorImpl extends BaseXmlElementDescriptorImpl implements PsiWritableMetaData {
  protected XmlElementDecl myElementDecl;
  private String myName;

  private static final Class[] ourParentClassesToScanAttributes = new Class[] { XmlMarkupDecl.class, XmlDocument.class };
  private static final Key> ourCachedAttlistKeys = Key.create("cached_declarations");

  public XmlElementDescriptorImpl(XmlElementDecl elementDecl) {
    init(elementDecl);
  }

  public XmlElementDescriptorImpl() {
  }

  private static final UserDataCache,XmlElement, Object> myAttlistDeclCache = new UserDataCache,XmlElement, Object>() {
    @Override
    protected final CachedValue compute(final XmlElement owner, Object o) {
      return CachedValuesManager.getManager(owner.getProject()).createCachedValue(new CachedValueProvider() {
        @Override
        public Result compute() {
          return new Result(doCollectAttlistDeclarations(owner),owner);
        }
      });
    }
  };

  @Override
  public PsiElement getDeclaration(){
    return myElementDecl;
  }

  @Override
  public String getName(PsiElement context){
    return getName();
  }

  @Override
  public String getName() {
    if (myName!=null) return myName;
    return myName = myElementDecl.getName();
  }

  @Override
  public void init(PsiElement element){
    myElementDecl = (XmlElementDecl) element;
  }

  @Override
  @SuppressWarnings("SpellCheckingInspection")
  public Object[] getDependences(){
    return new Object[]{myElementDecl, ExternalResourceManager.getInstance()};
  }

  @Override
  public XmlNSDescriptor getNSDescriptor() {
    return getNsDescriptorFrom(myElementDecl);
  }

  @Nullable
  private static XmlNSDescriptor getNsDescriptorFrom(final PsiElement elementDecl) {
    final XmlFile file = XmlUtil.getContainingFile(elementDecl);
    if (file == null) {
      return null;
    }
    final XmlDocument document = file.getDocument();
    assert document != null;
    XmlNSDescriptor descriptor = (XmlNSDescriptor)document.getMetaData();
    return descriptor == null ? document.getDefaultNSDescriptor(XmlUtil.EMPTY_URI, false) : descriptor;
  }

  // Read-only action
  @Override
  protected final XmlElementDescriptor[] doCollectXmlDescriptors(final XmlTag context) {
    final LinkedHashSet result = new LinkedHashSet();
    final XmlElementContentSpec contentSpecElement = myElementDecl.getContentSpecElement();
    final XmlNSDescriptor nsDescriptor = getNSDescriptor();
    final XmlNSDescriptor NSDescriptor = nsDescriptor != null? nsDescriptor:getNsDescriptorFrom(context);
    
    XmlUtil.processXmlElements(contentSpecElement, new PsiElementProcessor(){
      @Override
      public boolean execute(@NotNull PsiElement child){
        if (child instanceof XmlToken) {
          final XmlToken token = (XmlToken)child;

          if (token.getTokenType() == XmlTokenType.XML_NAME) {
            final String text = child.getText();
            XmlElementDescriptor element = getElementDescriptor(text, NSDescriptor);

            if (element != null) {
              result.add(element);
            }
          }
          else if (token.getTokenType() == XmlTokenType.XML_CONTENT_ANY) {
            if (NSDescriptor instanceof XmlNSDescriptorImpl) {
              ContainerUtil.addAll(result, ((XmlNSDescriptorImpl)NSDescriptor).getElements());
            } else if (NSDescriptor instanceof XmlNSDescriptorSequence) {

              for (XmlNSDescriptor xmlNSDescriptor : ((XmlNSDescriptorSequence)NSDescriptor).getSequence()) {
                if (xmlNSDescriptor instanceof XmlNSDescriptorImpl) {
                  ContainerUtil.addAll(result, ((XmlNSDescriptorImpl)xmlNSDescriptor).getElements());
                }
              }
            }
          }
        }
        return true;
      }
    }, true, false, XmlUtil.getContainingFile(getDeclaration()));

    return result.toArray(new XmlElementDescriptor[result.size()]);
  }

  private static XmlElementDescriptor getElementDescriptor(final String text, final XmlNSDescriptor NSDescriptor) {
    XmlElementDescriptor element = null;
    if (NSDescriptor instanceof XmlNSDescriptorImpl) {
      element = ((XmlNSDescriptorImpl)NSDescriptor).getElementDescriptor(text);
    }
    else if (NSDescriptor instanceof XmlNSDescriptorSequence) {
      final List sequence = ((XmlNSDescriptorSequence)NSDescriptor).getSequence();
      for (XmlNSDescriptor xmlNSDescriptor : sequence) {
        if (xmlNSDescriptor instanceof XmlNSDescriptorImpl) {
          element = ((XmlNSDescriptorImpl)xmlNSDescriptor).getElementDescriptor(text);
          if(element != null) break;
        }
      }
    }
    else {
      element = null;
    }
    return element;
  }

  // Read-only calculation
  @Override
  protected final XmlAttributeDescriptor[] collectAttributeDescriptors(final XmlTag context) {
    final List result = new SmartList();
    for (XmlAttlistDecl attlistDecl : findAttlistDeclarations(getName())) {
      for (XmlAttributeDecl attributeDecl : attlistDecl.getAttributeDecls()) {
        final PsiMetaData psiMetaData = attributeDecl.getMetaData();
        assert psiMetaData instanceof XmlAttributeDescriptor;
        result.add((XmlAttributeDescriptor)psiMetaData);
      }
    }
    return result.toArray(new XmlAttributeDescriptor[result.size()]);
  }

  // Read-only calculation
  @Override
  protected HashMap collectAttributeDescriptorsMap(final XmlTag context) {
    final HashMap localADM;
    final XmlAttributeDescriptor[] xmlAttributeDescriptors = getAttributesDescriptors(context);
    localADM = new HashMap(xmlAttributeDescriptors.length);

    for (final XmlAttributeDescriptor xmlAttributeDescriptor : xmlAttributeDescriptors) {
      localADM.put(xmlAttributeDescriptor.getName(), xmlAttributeDescriptor);
    }
    return localADM;
  }

  private XmlAttlistDecl[] findAttlistDeclarations(String elementName) {
    final List result = new ArrayList();
    for (final XmlAttlistDecl declaration : getAttlistDeclarations()) {
      final String name = declaration.getName();
      if (name != null && name.equals(elementName)) {
        result.add(declaration);
      }
    }
    return result.toArray(new XmlAttlistDecl[result.size()]);
  }

  private XmlAttlistDecl[] getAttlistDeclarations() {
    return getCachedAttributeDeclarations((XmlElement)getDeclaration());
  }

  public static @NotNull XmlAttlistDecl[] getCachedAttributeDeclarations(@Nullable XmlElement owner) {
    if (owner == null) return XmlAttlistDecl.EMPTY_ARRAY;
    owner = (XmlElement)PsiTreeUtil.getParentOfType(owner, ourParentClassesToScanAttributes);
    if (owner == null) return XmlAttlistDecl.EMPTY_ARRAY;
    return myAttlistDeclCache.get(ourCachedAttlistKeys, owner, null).getValue();
  }

  private static XmlAttlistDecl[] doCollectAttlistDeclarations(XmlElement xmlElement) {
    final List result = new ArrayList();
    XmlUtil.processXmlElements(xmlElement, new FilterElementProcessor(new ClassFilter(XmlAttlistDecl.class), result), false, false, XmlUtil.getContainingFile(xmlElement));
    return result.toArray(new XmlAttlistDecl[result.size()]);
  }

  @Override
  public XmlElementsGroup getTopGroup() {
    XmlElementContentGroup topGroup = myElementDecl.getContentSpecElement().getTopGroup();
    return topGroup == null ? null : new XmlElementsGroupImpl(topGroup, null);
  }

  @Override
  public int getContentType() {
    if (myElementDecl.getContentSpecElement().isAny()) {
      return CONTENT_TYPE_ANY;
    }
    if (myElementDecl.getContentSpecElement().hasChildren()) {
      return CONTENT_TYPE_CHILDREN;
    }
    if (myElementDecl.getContentSpecElement().isEmpty()) {
      return CONTENT_TYPE_EMPTY;
    }
    if (myElementDecl.getContentSpecElement().isMixed()) {
      return CONTENT_TYPE_MIXED;
    }

    return CONTENT_TYPE_ANY;
  }

  // Read-only calculation
  @Override
  protected HashMap collectElementDescriptorsMap(final XmlTag element) {
    final HashMap elementDescriptorsMap;
    final XmlElementDescriptor[] descriptors = getElementsDescriptors(element);
    elementDescriptorsMap = new HashMap(descriptors.length);

    for (final XmlElementDescriptor descriptor : descriptors) {
      elementDescriptorsMap.put(descriptor.getName(), descriptor);
    }
    return elementDescriptorsMap;
  }

  @Override
  public String getQualifiedName() {
    return getName();
  }

  @Override
  public String getDefaultName() {
    return getName();
  }

  @Override
  public void setName(final String name) throws IncorrectOperationException {
    // IDEADEV-11439
    myName = null;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy