diff options
Diffstat (limited to 'xml/xml-psi-impl/src/com/intellij')
12 files changed, 489 insertions, 517 deletions
diff --git a/xml/xml-psi-impl/src/com/intellij/javaee/ExternalResourceManagerExImpl.java b/xml/xml-psi-impl/src/com/intellij/javaee/ExternalResourceManagerExImpl.java index d030ccf9f189..13cfa9e13d2a 100644 --- a/xml/xml-psi-impl/src/com/intellij/javaee/ExternalResourceManagerExImpl.java +++ b/xml/xml-psi-impl/src/com/intellij/javaee/ExternalResourceManagerExImpl.java @@ -24,7 +24,10 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.*; +import com.intellij.openapi.util.AtomicNotNullLazyValue; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.NotNullLazyKey; +import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; @@ -46,9 +49,9 @@ import java.net.URL; import java.util.*; @State(name = "ExternalResourceManagerImpl", - storages = {@Storage( file = StoragePathMacros.APP_CONFIG + "/other.xml")}) -public class ExternalResourceManagerExImpl extends ExternalResourceManagerEx implements JDOMExternalizable { - static final Logger LOG = Logger.getInstance("#com.intellij.j2ee.openapi.impl.ExternalResourceManagerImpl"); + storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/other.xml")}) +public class ExternalResourceManagerExImpl extends ExternalResourceManagerEx implements PersistentStateComponent<Element> { + static final Logger LOG = Logger.getInstance(ExternalResourceManagerExImpl.class); @NonNls public static final String J2EE_1_3 = "http://java.sun.com/dtd/"; @NonNls public static final String J2EE_1_2 = "http://java.sun.com/j2ee/dtds/"; @@ -92,7 +95,6 @@ public class ExternalResourceManagerExImpl extends ExternalResourceManagerEx imp } private final List<ExternalResourceListener> myListeners = ContainerUtil.createLockFreeCopyOnWriteList(); - private final PathMacrosImpl myPathMacros; @NonNls private static final String RESOURCE_ELEMENT = "resource"; @NonNls private static final String URL_ATTR = "url"; @NonNls private static final String LOCATION_ATTR = "location"; @@ -100,10 +102,6 @@ public class ExternalResourceManagerExImpl extends ExternalResourceManagerEx imp @NonNls private static final String HTML_DEFAULT_DOCTYPE_ELEMENT = "default-html-doctype"; private static final String DEFAULT_VERSION = null; - public ExternalResourceManagerExImpl(@NotNull PathMacrosImpl pathMacros) { - myPathMacros = pathMacros; - } - @Override public boolean isStandardResource(VirtualFile file) { VirtualFile parent = file.getParent(); @@ -374,39 +372,11 @@ public class ExternalResourceManagerExImpl extends ExternalResourceManagerEx imp return getProjectResources(project).getModificationCount(); } - @Override - public void readExternal(Element element) { - final ExpandMacroToPathMap macroExpands = new ExpandMacroToPathMap(); - myPathMacros.addMacroExpands(macroExpands); - macroExpands.substitute(element, SystemInfo.isFileSystemCaseSensitive); - - incModificationCount(); - for (final Object o1 : element.getChildren(RESOURCE_ELEMENT)) { - Element e = (Element)o1; - addSilently(e.getAttributeValue(URL_ATTR), DEFAULT_VERSION, e.getAttributeValue(LOCATION_ATTR).replace('/', File.separatorChar)); - } - - for (final Object o : element.getChildren(IGNORED_RESOURCE_ELEMENT)) { - Element e = (Element)o; - addIgnoredSilently(e.getAttributeValue(URL_ATTR)); - } - - Element child = element.getChild(HTML_DEFAULT_DOCTYPE_ELEMENT); - if (child != null) { - String text = child.getText(); - if (FileUtil.toSystemIndependentName(text).endsWith(".jar!/resources/html5-schema/html5.rnc")) { - text = HTML5_DOCTYPE_ELEMENT; - } - myDefaultHtmlDoctype = text; - } - Element catalogElement = element.getChild(CATALOG_PROPERTIES_ELEMENT); - if (catalogElement != null) { - myCatalogPropertiesFile = catalogElement.getTextTrim(); - } - } + @Nullable @Override - public void writeExternal(Element element) { + public Element getState() { + Element element = new Element("state"); final String[] urls = getAvailableUrls(); for (String url : urls) { if (url == null) continue; @@ -440,9 +410,42 @@ public class ExternalResourceManagerExImpl extends ExternalResourceManagerEx imp final ReplacePathToMacroMap macroReplacements = new ReplacePathToMacroMap(); PathMacrosImpl.getInstanceEx().addMacroReplacements(macroReplacements); macroReplacements.substitute(element, SystemInfo.isFileSystemCaseSensitive); + return element; } @Override + public void loadState(Element element) { + final ExpandMacroToPathMap macroExpands = new ExpandMacroToPathMap(); + PathMacrosImpl.getInstanceEx().addMacroExpands(macroExpands); + macroExpands.substitute(element, SystemInfo.isFileSystemCaseSensitive); + + incModificationCount(); + for (final Object o1 : element.getChildren(RESOURCE_ELEMENT)) { + Element e = (Element)o1; + addSilently(e.getAttributeValue(URL_ATTR), DEFAULT_VERSION, e.getAttributeValue(LOCATION_ATTR).replace('/', File.separatorChar)); + } + + for (final Object o : element.getChildren(IGNORED_RESOURCE_ELEMENT)) { + Element e = (Element)o; + addIgnoredSilently(e.getAttributeValue(URL_ATTR)); + } + + Element child = element.getChild(HTML_DEFAULT_DOCTYPE_ELEMENT); + if (child != null) { + String text = child.getText(); + if (FileUtil.toSystemIndependentName(text).endsWith(".jar!/resources/html5-schema/html5.rnc")) { + text = HTML5_DOCTYPE_ELEMENT; + } + myDefaultHtmlDoctype = text; + } + Element catalogElement = element.getChild(CATALOG_PROPERTIES_ELEMENT); + if (catalogElement != null) { + myCatalogPropertiesFile = catalogElement.getTextTrim(); + } + } + + + @Override public void addExternalResourceListener(ExternalResourceListener listener) { myListeners.add(listener); } @@ -465,7 +468,7 @@ public class ExternalResourceManagerExImpl extends ExternalResourceManagerEx imp private static final NotNullLazyKey<ExternalResourceManagerExImpl, Project> INSTANCE_CACHE = ServiceManager.createLazyKey(ExternalResourceManagerExImpl.class); - private ExternalResourceManagerExImpl getProjectResources(Project project) { + private static ExternalResourceManagerExImpl getProjectResources(Project project) { return INSTANCE_CACHE.getValue(project); } diff --git a/xml/xml-psi-impl/src/com/intellij/javaee/InternalResourceProvider.java b/xml/xml-psi-impl/src/com/intellij/javaee/InternalResourceProvider.java index 673540ef38e8..38777922ee35 100644 --- a/xml/xml-psi-impl/src/com/intellij/javaee/InternalResourceProvider.java +++ b/xml/xml-psi-impl/src/com/intellij/javaee/InternalResourceProvider.java @@ -63,5 +63,6 @@ public class InternalResourceProvider implements StandardResourceProvider{ // svg and mathML impl.addIgnoredResource(HtmlUtil.MATH_ML_NAMESPACE); impl.addIgnoredResource(HtmlUtil.SVG_NAMESPACE); + impl.addInternalResource("http://www.w3.org/1999/xlink", "xlink.dtd"); } } diff --git a/xml/xml-psi-impl/src/com/intellij/javaee/ProjectResources.java b/xml/xml-psi-impl/src/com/intellij/javaee/ProjectResources.java index 916090996e7c..4b9541b0ebe2 100644 --- a/xml/xml-psi-impl/src/com/intellij/javaee/ProjectResources.java +++ b/xml/xml-psi-impl/src/com/intellij/javaee/ProjectResources.java @@ -16,42 +16,21 @@ package com.intellij.javaee; import com.intellij.application.options.PathMacrosImpl; -import com.intellij.openapi.components.PersistentStateComponent; import com.intellij.openapi.components.State; import com.intellij.openapi.components.Storage; import com.intellij.openapi.components.StoragePathMacros; -import com.intellij.openapi.util.JDOMExternalizable; -import com.intellij.openapi.util.JDOMExternalizableAdapter; -import org.jdom.Element; import org.jetbrains.annotations.NotNull; import java.util.Collections; import java.util.Map; /** -* @author Dmitry Avdeev -*/ -@State(name = "ProjectResources", storages = {@Storage( file = StoragePathMacros.PROJECT_FILE)}) -public class ProjectResources extends ExternalResourceManagerExImpl implements PersistentStateComponent<Element>, JDOMExternalizable { - private final JDOMExternalizableAdapter myAdapter; - - public ProjectResources(@NotNull PathMacrosImpl pathMacros) { - super(pathMacros); - myAdapter = new JDOMExternalizableAdapter(this, "ProjectResources"); - } - + * @author Dmitry Avdeev + */ +@State(name = "ProjectResources", storages = {@Storage(file = StoragePathMacros.PROJECT_FILE)}) +public class ProjectResources extends ExternalResourceManagerExImpl { @Override protected Map<String, Map<String, Resource>> computeStdResources() { - return Collections.emptyMap(); - } - - @Override - public Element getState() { - return myAdapter.getState(); - } - - @Override - public void loadState(Element state) { - myAdapter.loadState(state); + return Collections.emptyMap(); } } diff --git a/xml/xml-psi-impl/src/com/intellij/lexer/HtmlHighlightingLexer.java b/xml/xml-psi-impl/src/com/intellij/lexer/HtmlHighlightingLexer.java index eeae1d318e15..1d20283aa708 100644 --- a/xml/xml-psi-impl/src/com/intellij/lexer/HtmlHighlightingLexer.java +++ b/xml/xml-psi-impl/src/com/intellij/lexer/HtmlHighlightingLexer.java @@ -15,74 +15,41 @@ */ package com.intellij.lexer; -import com.intellij.lang.*; +import com.intellij.lang.HtmlInlineScriptTokenTypesProvider; +import com.intellij.lang.HtmlScriptContentProvider; +import com.intellij.lang.Language; +import com.intellij.lang.LanguageHtmlInlineScriptTokenTypesProvider; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.fileTypes.*; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.fileTypes.PlainTextLanguage; +import com.intellij.openapi.fileTypes.SyntaxHighlighter; +import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory; import com.intellij.psi.tree.IElementType; import com.intellij.psi.xml.XmlTokenType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.HashMap; +import java.util.Map; + public class HtmlHighlightingLexer extends BaseHtmlLexer { private static final Logger LOG = Logger.getInstance("#com.intellij.lexer.HtmlHighlightingLexer"); private static final int EMBEDDED_LEXER_ON = 0x1 << BASE_STATE_SHIFT; private static final int EMBEDDED_LEXER_STATE_SHIFT = BASE_STATE_SHIFT + 1; - - private Lexer embeddedLexer; - private Lexer styleLexer; - private Lexer scriptLexer; - protected Lexer elLexer; - private boolean hasNoEmbeddments; - private final FileType ourStyleFileType;// = FileTypeManager.getInstance().getStdFileType("CSS"); private static final FileType ourInlineScriptFileType; - - static { // At the moment only JS. HtmlInlineScriptTokenTypesProvider provider = LanguageHtmlInlineScriptTokenTypesProvider.getInlineScriptProvider(Language.findLanguageByID("JavaScript")); ourInlineScriptFileType = provider != null ? provider.getFileType() : null; } - - public class XmlEmbeddmentHandler implements TokenHandler { - @Override - public void handleElement(Lexer lexer) { - if (!hasSeenStyle() && !hasSeenScript() || hasNoEmbeddments) return; - final IElementType tokenType = lexer.getTokenType(); - - if (tokenType == XmlTokenType.XML_ATTRIBUTE_VALUE_TOKEN && hasSeenAttribute() || - tokenType == XmlTokenType.XML_DATA_CHARACTERS && hasSeenTag() || - tokenType == XmlTokenType.XML_COMMENT_CHARACTERS && hasSeenTag() - ) { - setEmbeddedLexer(); - - if (embeddedLexer != null) { - embeddedLexer.start( - getBufferSequence(), - HtmlHighlightingLexer.super.getTokenStart(), - skipToTheEndOfTheEmbeddment(), - embeddedLexer instanceof EmbedmentLexer ? ((EmbedmentLexer)embeddedLexer).getEmbeddedInitialState(tokenType) : 0 - ); - - if (embeddedLexer.getTokenType() == null) { - // no content for embeddment - embeddedLexer = null; - } - } - } - } - } - - public class ElEmbeddmentHandler implements TokenHandler { - @Override - public void handleElement(Lexer lexer) { - setEmbeddedLexer(); - if (embeddedLexer != null) { - embeddedLexer.start(getBufferSequence(), HtmlHighlightingLexer.super.getTokenStart(), HtmlHighlightingLexer.super.getTokenEnd()); - } - } - } + private final FileType ourStyleFileType;// = FileTypeManager.getInstance().getStdFileType("CSS"); + protected Lexer elLexer; + private Lexer embeddedLexer; + private Lexer styleLexer; + private Map<String, Lexer> scriptLexers = new HashMap<String, Lexer>(); + private boolean hasNoEmbeddments; public HtmlHighlightingLexer() { this(null); @@ -114,7 +81,7 @@ public class HtmlHighlightingLexer extends BaseHtmlLexer { } else { embeddedLexer = null; - scriptLexer = null; + scriptLexers.clear(); } } @@ -122,14 +89,20 @@ public class HtmlHighlightingLexer extends BaseHtmlLexer { Lexer newLexer = null; if (hasSeenStyle()) { if (styleLexer == null) { - styleLexer = ourStyleFileType == null - ? null - : SyntaxHighlighterFactory.getSyntaxHighlighter(ourStyleFileType, null, null).getHighlightingLexer(); + if (ourStyleFileType == null) { + styleLexer = null; + } + else { + SyntaxHighlighter highlighter = SyntaxHighlighterFactory.getSyntaxHighlighter(ourStyleFileType, null, null); + LOG.assertTrue(highlighter != null, ourStyleFileType); + styleLexer = highlighter.getHighlightingLexer(); + } } newLexer = styleLexer; } else if (hasSeenScript()) { + Lexer scriptLexer = scriptLexers.get(scriptType); if (scriptLexer == null) { if (hasSeenTag()) { HtmlScriptContentProvider provider = findScriptContentProvider(scriptType); @@ -145,6 +118,7 @@ public class HtmlHighlightingLexer extends BaseHtmlLexer { ourInlineScriptFileType != null ? SyntaxHighlighterFactory.getSyntaxHighlighter(ourInlineScriptFileType, null, null) : null; scriptLexer = syntaxHighlighter != null ? syntaxHighlighter.getHighlightingLexer() : null; } + scriptLexers.put(scriptType, scriptLexer); } newLexer = scriptLexer; } @@ -254,4 +228,43 @@ public class HtmlHighlightingLexer extends BaseHtmlLexer { public void setHasNoEmbeddments(boolean hasNoEmbeddments) { this.hasNoEmbeddments = hasNoEmbeddments; } + + public class XmlEmbeddmentHandler implements TokenHandler { + @Override + public void handleElement(Lexer lexer) { + if (!hasSeenStyle() && !hasSeenScript() || hasNoEmbeddments) return; + final IElementType tokenType = lexer.getTokenType(); + + if (tokenType == XmlTokenType.XML_ATTRIBUTE_VALUE_TOKEN && hasSeenAttribute() || + tokenType == XmlTokenType.XML_DATA_CHARACTERS && hasSeenTag() || + tokenType == XmlTokenType.XML_COMMENT_CHARACTERS && hasSeenTag() + ) { + setEmbeddedLexer(); + + if (embeddedLexer != null) { + embeddedLexer.start( + getBufferSequence(), + HtmlHighlightingLexer.super.getTokenStart(), + skipToTheEndOfTheEmbeddment(), + embeddedLexer instanceof EmbedmentLexer ? ((EmbedmentLexer)embeddedLexer).getEmbeddedInitialState(tokenType) : 0 + ); + + if (embeddedLexer.getTokenType() == null) { + // no content for embeddment + embeddedLexer = null; + } + } + } + } + } + + public class ElEmbeddmentHandler implements TokenHandler { + @Override + public void handleElement(Lexer lexer) { + setEmbeddedLexer(); + if (embeddedLexer != null) { + embeddedLexer.start(getBufferSequence(), HtmlHighlightingLexer.super.getTokenStart(), HtmlHighlightingLexer.super.getTokenEnd()); + } + } + } } diff --git a/xml/xml-psi-impl/src/com/intellij/psi/XmlElementFactoryImpl.java b/xml/xml-psi-impl/src/com/intellij/psi/XmlElementFactoryImpl.java index 6f40f853b777..20abde77589e 100644 --- a/xml/xml-psi-impl/src/com/intellij/psi/XmlElementFactoryImpl.java +++ b/xml/xml-psi-impl/src/com/intellij/psi/XmlElementFactoryImpl.java @@ -23,6 +23,7 @@ import com.intellij.lang.Language; import com.intellij.lang.xml.XMLLanguage; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.fileTypes.LanguageFileType; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.xml.*; @@ -109,7 +110,17 @@ public class XmlElementFactoryImpl extends XmlElementFactory { } private XmlDocument createXmlDocument(@NonNls final CharSequence text, @NonNls final String fileName, FileType fileType) { - final XmlDocument document = ((XmlFile)PsiFileFactory.getInstance(myProject).createFileFromText(fileName, fileType, text)).getDocument(); + PsiFile fileFromText = PsiFileFactory.getInstance(myProject).createFileFromText(fileName, fileType, text); + + XmlFile xmlFile; + if (fileFromText instanceof XmlFile) { + xmlFile = (XmlFile)fileFromText; + } + else { + xmlFile = (XmlFile)fileFromText.getViewProvider().getPsi(((LanguageFileType)fileType).getLanguage()); + assert xmlFile != null; + } + XmlDocument document = xmlFile.getDocument(); assert document != null; return document; } diff --git a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/manipulators/XmlAttributeValueManipulator.java b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/manipulators/XmlAttributeValueManipulator.java index a32b51f5fc3f..92c287e8fdbe 100644 --- a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/manipulators/XmlAttributeValueManipulator.java +++ b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/manipulators/XmlAttributeValueManipulator.java @@ -30,6 +30,7 @@ import com.intellij.psi.xml.XmlAttributeValue; import com.intellij.psi.xml.XmlTokenType; import com.intellij.util.CharTable; import com.intellij.util.IncorrectOperationException; +import com.intellij.xml.util.XmlUtil; import org.jetbrains.annotations.NotNull; /** @@ -63,7 +64,7 @@ public class XmlAttributeValueManipulator extends AbstractElementManipulator<Xml final int offsetInParent = elementToReplace.getStartOffsetInParent(); String textBeforeRange = text.substring(0, range.getStartOffset() - offsetInParent); String textAfterRange = text.substring(range.getEndOffset()- offsetInParent, text.length()); - text = textBeforeRange + newContent + textAfterRange; + text = textBeforeRange + XmlUtil.escape(newContent) + textAfterRange; } catch(StringIndexOutOfBoundsException e) { LOG.error("Range: " + range + " in text: '" + element.getText() + "'", e); throw e; diff --git a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/manipulators/XmlTextManipulator.java b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/manipulators/XmlTextManipulator.java index de4f9eb6cbc7..e160ba4c14db 100644 --- a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/manipulators/XmlTextManipulator.java +++ b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/manipulators/XmlTextManipulator.java @@ -51,6 +51,9 @@ public class XmlTextManipulator extends AbstractElementManipulator<XmlText> { else { text.deleteChildRange(text.getFirstChild(), text.getLastChild()); } + //String oldText = text.getText(); + //((PsiLanguageInjectionHost)text).updateText( + // oldText.substring(0, range.getStartOffset()) + newContent + oldText.substring(range.getEndOffset())); return text; } diff --git a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/XmlTagImpl.java b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/XmlTagImpl.java index 1c33789dfd57..dd70733533f8 100644 --- a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/XmlTagImpl.java +++ b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/XmlTagImpl.java @@ -75,27 +75,8 @@ import java.util.*; public class XmlTagImpl extends XmlElementImpl implements XmlTag { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.xml.XmlTagImpl"); - - private volatile String myName = null; - private volatile String myLocalName; - private volatile XmlAttribute[] myAttributes = null; - private volatile Map<String, String> myAttributeValueMap = null; - private volatile XmlTagValue myValue = null; - private volatile Map<String, CachedValue<XmlNSDescriptor>> myNSDescriptorsMap = null; - private volatile String myCachedNamespace; - private volatile long myModCount; - - private volatile XmlElementDescriptor myCachedDescriptor; - private volatile long myDescriptorModCount = -1; - private volatile long myExtResourcesModCount = -1; - - private volatile boolean myHasNamespaceDeclarations = false; - private volatile BidirectionalMap<String, String> myNamespaceMap = null; @NonNls private static final String XML_NS_PREFIX = "xml"; - - private final int myHC = ourHC++; private static final RecursionGuard ourGuard = RecursionManager.createGuard("xmlTag"); - private static final Key<ParameterizedCachedValue<XmlTag[], XmlTagImpl>> SUBTAGS_KEY = Key.create("subtags"); private static final ParameterizedCachedValueProvider<XmlTag[],XmlTagImpl> CACHED_VALUE_PROVIDER = new ParameterizedCachedValueProvider<XmlTag[], XmlTagImpl>() { @@ -111,11 +92,20 @@ public class XmlTagImpl extends XmlElementImpl implements XmlTag { .create(tags, PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT, tag.getContainingFile()); } }; - - @Override - public final int hashCode() { - return myHC; - } + private final int myHC = ourHC++; + private volatile String myName = null; + private volatile String myLocalName; + private volatile XmlAttribute[] myAttributes = null; + private volatile Map<String, String> myAttributeValueMap = null; + private volatile XmlTagValue myValue = null; + private volatile Map<String, CachedValue<XmlNSDescriptor>> myNSDescriptorsMap = null; + private volatile String myCachedNamespace; + private volatile long myModCount; + private volatile XmlElementDescriptor myCachedDescriptor; + private volatile long myDescriptorModCount = -1; + private volatile long myExtResourcesModCount = -1; + private volatile boolean myHasNamespaceDeclarations = false; + private volatile BidirectionalMap<String, String> myNamespaceMap = null; public XmlTagImpl() { this(XmlElementType.XML_TAG); @@ -125,6 +115,33 @@ public class XmlTagImpl extends XmlElementImpl implements XmlTag { super(type); } + @Nullable + private static XmlNSDescriptor getDtdDescriptor(@NotNull XmlFile containingFile) { + final XmlDocument document = containingFile.getDocument(); + if (document == null) { + return null; + } + final String url = XmlUtil.getDtdUri(document); + if (url == null) { + return null; + } + return document.getDefaultNSDescriptor(url, true); + } + + @Nullable + private static String getNSVersion(String ns, final XmlTagImpl xmlTag) { + String versionValue = xmlTag.getAttributeValue("version"); + if (versionValue != null && xmlTag.getNamespace().equals(ns)) { + return versionValue; + } + return null; + } + + @Override + public final int hashCode() { + return myHC; + } + @Override public void clearCaches() { myName = null; @@ -215,19 +232,6 @@ public class XmlTagImpl extends XmlElementImpl implements XmlTag { return parentTag.getNSDescriptor(namespace, strict); } - @Nullable - private static XmlNSDescriptor getDtdDescriptor(@NotNull XmlFile containingFile) { - final XmlDocument document = containingFile.getDocument(); - if (document == null) { - return null; - } - final String url = XmlUtil.getDtdUri(document); - if (url == null) { - return null; - } - return document.getDefaultNSDescriptor(url, true); - } - @Override public boolean isEmpty() { return XmlChildRole.CLOSING_TAG_START_FINDER.findChild(this) == null; @@ -325,15 +329,6 @@ public class XmlTagImpl extends XmlElementImpl implements XmlTag { return map == null ? Collections.<String, CachedValue<XmlNSDescriptor>>emptyMap() : map; } - @Nullable - private static String getNSVersion(String ns, final XmlTagImpl xmlTag) { - String versionValue = xmlTag.getAttributeValue("version"); - if (versionValue != null && xmlTag.getNamespace().equals(ns)) { - return versionValue; - } - return null; - } - private Map<String, CachedValue<XmlNSDescriptor>> initializeSchema(@NotNull final String namespace, @Nullable final String version, final String fileLocation, @@ -921,7 +916,7 @@ public class XmlTagImpl extends XmlElementImpl implements XmlTag { } } } - return ns; + return XmlUtil.getSchemaLocation(this, ns); } protected String getRealNs(final String value) { diff --git a/xml/xml-psi-impl/src/com/intellij/xml/HtmlXmlExtension.java b/xml/xml-psi-impl/src/com/intellij/xml/HtmlXmlExtension.java index 4ece939ffac0..e54a93394242 100644 --- a/xml/xml-psi-impl/src/com/intellij/xml/HtmlXmlExtension.java +++ b/xml/xml-psi-impl/src/com/intellij/xml/HtmlXmlExtension.java @@ -3,6 +3,7 @@ package com.intellij.xml; import com.intellij.ide.highlighter.HtmlFileType; import com.intellij.psi.PsiFile; import com.intellij.psi.xml.XmlDocument; +import com.intellij.xml.util.HtmlUtil; import org.jetbrains.annotations.Nullable; /** @@ -19,6 +20,16 @@ public class HtmlXmlExtension extends DefaultXmlExtension { @Nullable @Override public String[][] getNamespacesFromDocument(XmlDocument parent, boolean declarationsExist) { - return super.getNamespacesFromDocument(parent, false); + String[][] namespaces = super.getNamespacesFromDocument(parent, false); + if (namespaces == null || !HtmlUtil.isHtml5Document(parent)) return namespaces; + + for (String[] namespace : namespaces) { + if ("xlink".equals(namespace[0])) return namespaces; + } + + String[][] newNamespaces = new String[namespaces.length + 1][2]; + System.arraycopy(namespaces, 0, newNamespaces, 0, namespaces.length); + newNamespaces[namespaces.length] = new String[] {"xlink", "http://www.w3.org/1999/xlink"}; + return newNamespaces; } } diff --git a/xml/xml-psi-impl/src/com/intellij/xml/XmlCoreEnvironment.java b/xml/xml-psi-impl/src/com/intellij/xml/XmlCoreEnvironment.java index b7704fb3b981..4610c2fa97e0 100644 --- a/xml/xml-psi-impl/src/com/intellij/xml/XmlCoreEnvironment.java +++ b/xml/xml-psi-impl/src/com/intellij/xml/XmlCoreEnvironment.java @@ -119,7 +119,7 @@ public class XmlCoreEnvironment { appEnvironment.addExtension(StandardResourceProvider.EP_NAME, new InternalResourceProvider()); appEnvironment.registerApplicationComponent(PathMacros.class, new PathMacrosImpl()); - appEnvironment.registerApplicationService(ExternalResourceManager.class, new ExternalResourceManagerExImpl(PathMacrosImpl.getInstanceEx())); + appEnvironment.registerApplicationService(ExternalResourceManager.class, new ExternalResourceManagerExImpl()); appEnvironment.registerApplicationService(XmlFoldingSettings.class, new XmlFoldingSettings()); Language[] myLanguages = new Language[]{XMLLanguage.INSTANCE, HTMLLanguage.INSTANCE, XHTMLLanguage.INSTANCE, DTDLanguage.INSTANCE}; for (Language myLanguage : myLanguages) { @@ -137,8 +137,7 @@ public class XmlCoreEnvironment { public static class ProjectEnvironment { public ProjectEnvironment(CoreProjectEnvironment projectEnvironment) { projectEnvironment.getProject().registerService(XmlElementFactory.class, new XmlElementFactoryImpl(projectEnvironment.getProject())); - projectEnvironment.getProject().registerService(ExternalResourceManagerExImpl.class, - new ProjectResources(PathMacrosImpl.getInstanceEx())); + projectEnvironment.getProject().registerService(ExternalResourceManagerExImpl.class, new ProjectResources()); } } } diff --git a/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/XmlNSDescriptorImpl.java b/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/XmlNSDescriptorImpl.java index 192c272a5f23..17c6f1ab37ae 100644 --- a/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/XmlNSDescriptorImpl.java +++ b/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/XmlNSDescriptorImpl.java @@ -30,7 +30,6 @@ import com.intellij.psi.util.CachedValue; import com.intellij.psi.util.CachedValueProvider; import com.intellij.psi.util.CachedValuesManager; import com.intellij.psi.util.PsiModificationTracker; -import com.intellij.psi.xml.XmlAttribute; import com.intellij.psi.xml.XmlDocument; import com.intellij.psi.xml.XmlFile; import com.intellij.psi.xml.XmlTag; @@ -56,35 +55,35 @@ import java.util.*; */ @SuppressWarnings({"HardCodedStringLiteral"}) public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocument>, DumbAware, XmlNSTypeDescriptorProvider { - private static final Logger LOG = Logger.getInstance("#com.intellij.xml.impl.schema.XmlNSDescriptorImpl"); - @NonNls private static final Set<String> STD_TYPES = new HashSet<String>(); - private static final Set<String> UNDECLARED_STD_TYPES = new HashSet<String>(); - private XmlFile myFile; - private XmlTag myTag; - private String myTargetNamespace; @NonNls public static final String XSD_PREFIX = "xsd"; - + @NonNls public static final String SCHEMA_TAG_NAME = "schema"; + @NonNls public static final String IMPORT_TAG_NAME = "import"; @NonNls static final String ELEMENT_TAG_NAME = "element"; @NonNls static final String ATTRIBUTE_TAG_NAME = "attribute"; @NonNls static final String COMPLEX_TYPE_TAG_NAME = "complexType"; @NonNls static final String SEQUENCE_TAG_NAME = "sequence"; - @NonNls public static final String SCHEMA_TAG_NAME = "schema"; + private static final Logger LOG = Logger.getInstance("#com.intellij.xml.impl.schema.XmlNSDescriptorImpl"); + @NonNls private static final Set<String> STD_TYPES = new HashSet<String>(); + private static final Set<String> UNDECLARED_STD_TYPES = new HashSet<String>(); @NonNls private static final String INCLUDE_TAG_NAME = "include"; - @NonNls public static final String IMPORT_TAG_NAME = "import"; @NonNls private static final String REDEFINE_TAG_NAME = "redefine"; + private static final ThreadLocal<Set<PsiFile>> myRedefinedDescriptorsInProcessing = new ThreadLocal<Set<PsiFile>>(); + private final Map<QNameKey, CachedValue<XmlElementDescriptor>> myDescriptorsMap = Collections.synchronizedMap(new HashMap<QNameKey, CachedValue<XmlElementDescriptor>>()); + private final Map<Pair<QNameKey, XmlTag>, CachedValue<TypeDescriptor>> myTypesMap = Collections.synchronizedMap(new HashMap<Pair<QNameKey,XmlTag>, CachedValue<TypeDescriptor>>()); + private XmlFile myFile; + private XmlTag myTag; + private String myTargetNamespace; + private volatile Object[] dependencies; + private MultiMap<String,XmlTag> mySubstitutions; public XmlNSDescriptorImpl(XmlFile file) { init(file.getDocument()); } - + public XmlNSDescriptorImpl() { } - private volatile Object[] dependencies; - - private static final ThreadLocal<Set<PsiFile>> myRedefinedDescriptorsInProcessing = new ThreadLocal<Set<PsiFile>>(); - private static void collectDependencies(@Nullable XmlTag myTag, @NotNull XmlFile myFile, @NotNull Set<PsiFile> visited) { if (visited.contains(myFile)) return; visited.add( myFile ); @@ -121,7 +120,7 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum 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 == null) resourceLocation = ExternalResourceManager.getInstance().getResourceLocation(uri, myFile, null); if (resourceLocation instanceof XmlFile) addDependency((XmlFile)resourceLocation, visited); } @@ -136,6 +135,211 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum } } + private static boolean checkSchemaNamespace(String name, XmlTag context){ + final String namespace = context.getNamespaceByPrefix(XmlUtil.findPrefixByQualifiedName(name)); + if(namespace.length() > 0){ + return checkSchemaNamespace(namespace); + } + return XSD_PREFIX.equals(XmlUtil.findPrefixByQualifiedName(name)); + } + + public static boolean checkSchemaNamespace(String namespace) { + return XmlUtil.XML_SCHEMA_URI.equals(namespace) || + XmlUtil.XML_SCHEMA_URI2.equals(namespace) || + XmlUtil.XML_SCHEMA_URI3.equals(namespace); + } + + public static boolean checkSchemaNamespace(XmlTag context) { + LOG.assertTrue(context.isValid()); + final String namespace = context.getNamespace(); + if (namespace.length() > 0) { + return checkSchemaNamespace(namespace); + } + return StringUtil.startsWithConcatenation(context.getName(), XSD_PREFIX, ":"); + } + + static @NotNull XmlNSDescriptorImpl getNSDescriptorToSearchIn(XmlTag rootTag, final String name, XmlNSDescriptorImpl defaultNSDescriptor) { + if (name == null) return defaultNSDescriptor; + final String namespacePrefix = XmlUtil.findPrefixByQualifiedName(name); + + if (namespacePrefix.length() > 0) { + final String namespace = rootTag.getNamespaceByPrefix(namespacePrefix); + final XmlNSDescriptor nsDescriptor = rootTag.getNSDescriptor(namespace, true); + + if (nsDescriptor instanceof XmlNSDescriptorImpl) { + return (XmlNSDescriptorImpl)nsDescriptor; + } + } + + return defaultNSDescriptor; + } + + @Nullable + private static XmlElementDescriptor getDescriptorFromParent(final XmlTag tag, XmlElementDescriptor elementDescriptor) { + final PsiElement parent = tag.getParent(); + if (parent instanceof XmlTag) { + final XmlElementDescriptor descriptor = ((XmlTag)parent).getDescriptor(); + if (descriptor != null) elementDescriptor = descriptor.getElementDescriptor(tag, (XmlTag)parent); + } + return elementDescriptor; + } + + public static boolean processTagsInNamespace(@NotNull final XmlTag rootTag, String[] tagNames, PsiElementProcessor<XmlTag> processor) { + return processTagsInNamespaceInner(rootTag, tagNames, processor, null); + } + + 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.findNamespace(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 boolean equalsToSchemaName(@NotNull XmlTag tag, @NonNls String schemaName) { + return schemaName.equals(tag.getLocalName()) && checkSchemaNamespace(tag); + } + + 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 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.contains(":") && 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.findNamespace(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 static XmlNSDescriptorImpl getRedefinedElementDescriptor(final XmlTag parentTag) { + XmlFile file = getRedefinedElementDescriptorFile(parentTag); + if (file != null) { + final XmlDocument document = file.getDocument(); + final PsiMetaData metaData = document != null ? document.getMetaData():null; + if (metaData instanceof XmlNSDescriptorImpl) return (XmlNSDescriptorImpl)metaData; + } + return null; + } + + 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; + } + @Override public XmlFile getDescriptorFile() { return myFile; @@ -150,18 +354,10 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum return myTargetNamespace != null ? myTargetNamespace : ""; } - static class QNameKey extends Pair<String, String>{ - QNameKey(String name, String namespace) { - super(name, namespace); - } - } - private final Map<QNameKey, CachedValue<XmlElementDescriptor>> myDescriptorsMap = Collections.synchronizedMap(new HashMap<QNameKey, CachedValue<XmlElementDescriptor>>()); - private final Map<Pair<QNameKey, XmlTag>, CachedValue<TypeDescriptor>> myTypesMap = Collections.synchronizedMap(new HashMap<Pair<QNameKey,XmlTag>, CachedValue<TypeDescriptor>>()); - @Override @Nullable public XmlElementDescriptor getElementDescriptor(String localName, String namespace) { - return getElementDescriptor(localName, namespace, new HashSet<XmlNSDescriptorImpl>(),false); + return getElementDescriptor(localName, namespace, new HashSet<XmlNSDescriptorImpl>(), false); } @Nullable @@ -213,9 +409,9 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum ) ) ) { - final XmlAttribute schemaLocation = tag.getAttribute("schemaLocation"); + final String schemaLocation = tag.getAttributeValue("schemaLocation"); if (schemaLocation != null) { - final XmlFile xmlFile = XmlUtil.findNamespace(rootTag.getContainingFile(), schemaLocation.getValue()); + final XmlFile xmlFile = XmlUtil.findNamespace(rootTag.getContainingFile(), schemaLocation); if (xmlFile != null) { final XmlDocument includedDocument = xmlFile.getDocument(); if (includedDocument != null) { @@ -266,8 +462,7 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum return true; } else { - final boolean b = myTargetNamespace.equals(namespace); - if (b) return b; + if (myTargetNamespace.equals(namespace)) return true; return context.getNSDescriptor(namespace, true) == this; // schema's targetNamespace could be different from file systemId } return false; @@ -311,10 +506,10 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum namespace.equals(tag.getAttributeValue("namespace")) ) ) { - final XmlAttribute schemaLocation = tag.getAttribute("schemaLocation"); + final String schemaLocation = tag.getAttributeValue("schemaLocation"); if (schemaLocation != null) { - final XmlFile xmlFile = XmlUtil.findNamespace(myTag.getContainingFile(), schemaLocation.getValue()); + final XmlFile xmlFile = XmlUtil.findNamespace(myTag.getContainingFile(), schemaLocation); if (xmlFile != null) { @@ -370,7 +565,7 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum public TypeDescriptor getTypeDescriptor(final String name, XmlTag context) { if(checkSchemaNamespace(name, context)){ final String localNameByQualifiedName = XmlUtil.findLocalNameByQualifiedName(name); - + if (STD_TYPES.contains(localNameByQualifiedName) && ( name.length() == localNameByQualifiedName.length() || UNDECLARED_STD_TYPES.contains(localNameByQualifiedName) @@ -390,45 +585,6 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum return new XmlElementDescriptorByType(instanceTag, (ComplexTypeDescriptor)typeDescriptor); } - private static boolean checkSchemaNamespace(String name, XmlTag context){ - final String namespace = context.getNamespaceByPrefix(XmlUtil.findPrefixByQualifiedName(name)); - if(namespace.length() > 0){ - return checkSchemaNamespace(namespace); - } - return XSD_PREFIX.equals(XmlUtil.findPrefixByQualifiedName(name)); - } - - public static boolean checkSchemaNamespace(String namespace) { - return XmlUtil.XML_SCHEMA_URI.equals(namespace) || - XmlUtil.XML_SCHEMA_URI2.equals(namespace) || - XmlUtil.XML_SCHEMA_URI3.equals(namespace); - } - - public static boolean checkSchemaNamespace(XmlTag context) { - LOG.assertTrue(context.isValid()); - final String namespace = context.getNamespace(); - if (namespace.length() > 0) { - return checkSchemaNamespace(namespace); - } - return StringUtil.startsWithConcatenation(context.getName(), XSD_PREFIX, ":"); - } - - static @NotNull XmlNSDescriptorImpl getNSDescriptorToSearchIn(XmlTag rootTag, final String name, XmlNSDescriptorImpl defaultNSDescriptor) { - if (name == null) return defaultNSDescriptor; - final String namespacePrefix = XmlUtil.findPrefixByQualifiedName(name); - - if (namespacePrefix != null && namespacePrefix.length() > 0) { - final String namespace = rootTag.getNamespaceByPrefix(namespacePrefix); - final XmlNSDescriptor nsDescriptor = rootTag.getNSDescriptor(namespace, true); - - if (nsDescriptor instanceof XmlNSDescriptorImpl) { - return (XmlNSDescriptorImpl)nsDescriptor; - } - } - - return defaultNSDescriptor; - } - @Nullable protected TypeDescriptor findTypeDescriptor(final String qname) { return findTypeDescriptor(qname, myTag); @@ -587,7 +743,7 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum private boolean isSameName(@NotNull String name, String namespace, String nameAttribute) { return nameAttribute != null && - (nameAttribute.equals(name) || (name.indexOf(":") >= 0 && nameAttribute.equals(name.substring(name.indexOf(":") + 1)))) && + (nameAttribute.equals(name) || (name.contains(":") && nameAttribute.equals(name.substring(name.indexOf(":") + 1)))) && (namespace == null || namespace.length() == 0 || namespace.equals(getDefaultNamespace())) ; } @@ -619,23 +775,24 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum } private CachedValue<TypeDescriptor> createAndPutTypesCachedValue(final XmlTag tag, final Pair<QNameKey, XmlTag> pair) { - final CachedValue<TypeDescriptor> value = CachedValuesManager.getManager(tag.getProject()).createCachedValue(new CachedValueProvider<TypeDescriptor>() { - @Override - public CachedValueProvider.Result<TypeDescriptor> compute() { - final String name = tag.getAttributeValue("name"); - - if (name != null && - pair.first != null && - pair.first.first != null && - !name.equals(XmlUtil.findLocalNameByQualifiedName(pair.first.first)) - ) { - myTypesMap.remove(pair); - return new Result<TypeDescriptor>(null, PsiModificationTracker.MODIFICATION_COUNT); + final CachedValue<TypeDescriptor> value = CachedValuesManager.getManager(tag.getProject()).createCachedValue( + new CachedValueProvider<TypeDescriptor>() { + @Override + public CachedValueProvider.Result<TypeDescriptor> compute() { + final String name = tag.getAttributeValue("name"); + + if (name != null && + pair.first != null && + pair.first.first != null && + !name.equals(XmlUtil.findLocalNameByQualifiedName(pair.first.first)) + ) { + myTypesMap.remove(pair); + return new Result<TypeDescriptor>(null, PsiModificationTracker.MODIFICATION_COUNT); + } + final ComplexTypeDescriptor complexTypeDescriptor = new ComplexTypeDescriptor(XmlNSDescriptorImpl.this, tag); + return new Result<TypeDescriptor>(complexTypeDescriptor, tag); } - final ComplexTypeDescriptor complexTypeDescriptor = new ComplexTypeDescriptor(XmlNSDescriptorImpl.this, tag); - return new Result<TypeDescriptor>(complexTypeDescriptor, tag); - } - }, false); + }, false); myTypesMap.put(pair, value); return value; } @@ -668,7 +825,7 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum } else { XmlElementDescriptor elementDescriptor = getElementDescriptor(tag.getLocalName(), tag.getNamespace()); - + if (elementDescriptor == null) { elementDescriptor = getDescriptorFromParent(tag, elementDescriptor); } @@ -677,29 +834,19 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum } } - @Nullable - private static XmlElementDescriptor getDescriptorFromParent(final XmlTag tag, XmlElementDescriptor elementDescriptor) { - final PsiElement parent = tag.getParent(); - if (parent instanceof XmlTag) { - final XmlElementDescriptor descriptor = ((XmlTag)parent).getDescriptor(); - if (descriptor != null) elementDescriptor = descriptor.getElementDescriptor(tag, (XmlTag)parent); - } - return elementDescriptor; - } - @Override @NotNull public XmlElementDescriptor[] getRootElementsDescriptors(@Nullable final XmlDocument doc) { class CollectElementsProcessor implements PsiElementProcessor<XmlTag> { final List<XmlElementDescriptor> result = new ArrayList<XmlElementDescriptor>(); - + @Override public boolean execute(@NotNull final XmlTag element) { ContainerUtil.addIfNotNull(result, getElementDescriptor(element.getAttributeValue("name"), getDefaultNamespace())); return true; } } - + CollectElementsProcessor processor = new CollectElementsProcessor() { @Override public boolean execute(@NotNull final XmlTag element) { @@ -729,135 +876,6 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum return processor.result.toArray(new XmlAttributeDescriptor[processor.result.size()]); } - public static boolean processTagsInNamespace(@NotNull final XmlTag rootTag, String[] tagNames, PsiElementProcessor<XmlTag> processor) { - return processTagsInNamespaceInner(rootTag, tagNames, processor, null); - } - - 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.findNamespace(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 boolean equalsToSchemaName(@NotNull XmlTag tag, @NonNls String schemaName) { - return schemaName.equals(tag.getLocalName()) && checkSchemaNamespace(tag); - } - - 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 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.findNamespace(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; - } - @Nullable public XmlTag findGroup(String name) { return findSpecialTag(name,"group",myTag, this, null); @@ -865,11 +883,9 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum @Nullable public XmlTag findAttributeGroup(String name) { - return findSpecialTag(name,"attributeGroup",myTag,this, null); + return findSpecialTag(name, "attributeGroup", myTag, this, null); } - private MultiMap<String,XmlTag> mySubstitutions; - public XmlElementDescriptor[] getSubstitutes(String localName, String namespace) { if (!initSubstitutes()) { return XmlElementDescriptor.EMPTY_ARRAY; @@ -926,7 +942,7 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum @Override public void init(PsiElement element){ myFile = (XmlFile) element.getContainingFile(); - + if (element instanceof XmlTag) { myTag = (XmlTag)element; } else { @@ -955,7 +971,6 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum if (dependencies == null) dependencies = myFile == null ? ArrayUtil.EMPTY_OBJECT_ARRAY : new Object[] {myFile}; // init was not called return dependencies; } - static { STD_TYPES.add("string"); STD_TYPES.add("normalizedString"); @@ -1002,7 +1017,7 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum STD_TYPES.add("NMTOKEN"); STD_TYPES.add("NMTOKENS"); STD_TYPES.add("anySimpleType"); - + UNDECLARED_STD_TYPES.add("anySimpleType"); } @@ -1015,33 +1030,6 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum return myTag; } - public static XmlNSDescriptorImpl getRedefinedElementDescriptor(final XmlTag parentTag) { - XmlFile file = getRedefinedElementDescriptorFile(parentTag); - if (file != null) { - final XmlDocument document = file.getDocument(); - final PsiMetaData metaData = document != null ? document.getMetaData():null; - if (metaData instanceof XmlNSDescriptorImpl) return (XmlNSDescriptorImpl)metaData; - } - return null; - } - - 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; - } - public boolean hasSubstitutions() { initSubstitutes(); return mySubstitutions != null && mySubstitutions.size() > 0; @@ -1050,4 +1038,10 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum public boolean isValid() { return myFile != null && getDeclaration().isValid(); } + + static class QNameKey extends Pair<String, String>{ + QNameKey(String name, String namespace) { + super(name, namespace); + } + } } diff --git a/xml/xml-psi-impl/src/com/intellij/xml/util/XmlUtil.java b/xml/xml-psi-impl/src/com/intellij/xml/util/XmlUtil.java index a513db49b121..9de6d6e7e1d6 100644 --- a/xml/xml-psi-impl/src/com/intellij/xml/util/XmlUtil.java +++ b/xml/xml-psi-impl/src/com/intellij/xml/util/XmlUtil.java @@ -82,19 +82,14 @@ import java.util.*; * @author Mike */ public class XmlUtil { - private static final Logger LOG = Logger.getInstance("#com.intellij.xml.util.XmlUtil"); - @NonNls public static final String TAGLIB_1_2_URI = "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd"; - @NonNls public static final String XML_SCHEMA_URI = "http://www.w3.org/2001/XMLSchema"; @NonNls public static final String XML_SCHEMA_URI2 = "http://www.w3.org/1999/XMLSchema"; @NonNls public static final String XML_SCHEMA_URI3 = "http://www.w3.org/2000/10/XMLSchema"; public static final String[] SCHEMA_URIS = {XML_SCHEMA_URI, XML_SCHEMA_URI2, XML_SCHEMA_URI3}; @NonNls public static final String XML_SCHEMA_INSTANCE_URI = "http://www.w3.org/2001/XMLSchema-instance"; - @NonNls public static final String XSLT_URI = "http://www.w3.org/1999/XSL/Transform"; @NonNls public static final String XINCLUDE_URI = XmlPsiUtil.XINCLUDE_URI; - @NonNls public static final String ANT_URI = "http://ant.apache.org/schema.xsd"; @NonNls public static final String XHTML_URI = "http://www.w3.org/1999/xhtml"; @NonNls public static final String HTML_URI = "http://www.w3.org/1999/html"; @@ -102,31 +97,21 @@ public class XmlUtil { @NonNls public static final Key<String> TEST_PATH = Key.create("TEST PATH"); @NonNls public static final String JSP_URI = "http://java.sun.com/JSP/Page"; @NonNls public static final String ANY_URI = "http://www.intellij.net/ns/any"; - @NonNls public static final String JSTL_CORE_URI = "http://java.sun.com/jsp/jstl/core"; @NonNls public static final String JSTL_CORE_URI2 = "http://java.sun.com/jstl/core"; @NonNls public static final String JSTL_CORE_URI3 = "http://java.sun.com/jstl/core_rt"; @NonNls public static final String JSTL_CORE_URI_JAVAEE_7 = "http://xmlns.jcp.org/jsp/jstl/core"; - @NonNls public static final String[] JSTL_CORE_URIS = {JSTL_CORE_URI, JSTL_CORE_URI2, JSTL_CORE_URI3, JSTL_CORE_URI_JAVAEE_7}; - - @NonNls public static final String JSF_HTML_URI = "http://java.sun.com/jsf/html"; @NonNls public static final String JSF_HTML_URI_JAVAEE_7 = "http://xmlns.jcp.org/jsf/html"; @NonNls public static final String[] JSF_HTML_URIS = {JSF_HTML_URI, JSF_HTML_URI_JAVAEE_7}; - @NonNls public static final String JSF_CORE_URI = "http://java.sun.com/jsf/core"; @NonNls public static final String JSF_CORE_URI_JAVAEE_7 = "http://xmlns.jcp.org/jsf/core"; @NonNls public static final String[] JSF_CORE_URIS = {JSF_CORE_URI, JSF_CORE_URI_JAVAEE_7}; - @NonNls public static final String JSF_PASS_THROUGH_ATTR_URI_JAVAEE7 = "http://xmlns.jcp.org/jsf"; @NonNls public static final String JSF_PASSTHROUGH_URI = "http://xmlns.jcp.org/jsf/passthrough"; - @NonNls public static final String JSTL_FORMAT_URI = "http://java.sun.com/jsp/jstl/fmt"; @NonNls public static final String JSTL_FORMAT_URI2 = "http://java.sun.com/jstl/fmt"; - @NonNls private static final String JSTL_FORMAT_URI3 = "http://java.sun.com/jstl/fmt_rt"; - @NonNls public static final String[] JSTL_FORMAT_URIS = {JSTL_FORMAT_URI, JSTL_FORMAT_URI2, JSTL_FORMAT_URI3}; - @NonNls public static final String SPRING_URI = "http://www.springframework.org/tags"; @NonNls public static final String SPRING_FORMS_URI = "http://www.springframework.org/tags/form"; @NonNls public static final String STRUTS_BEAN_URI = "http://struts.apache.org/tags-bean"; @@ -135,26 +120,21 @@ public class XmlUtil { @NonNls public static final String STRUTS_LOGIC_URI = "http://struts.apache.org/tags-logic"; @NonNls public static final String STRUTS_HTML_URI = "http://struts.apache.org/tags-html"; @NonNls public static final String STRUTS_HTML_URI2 = "http://jakarta.apache.org/struts/tags-html"; - @NonNls public static final String APACHE_TRINIDAD_URI = "http://myfaces.apache.org/trinidad"; @NonNls public static final String APACHE_TRINIDAD_HTML_URI = "http://myfaces.apache.org/trinidad/html"; - @NonNls public static final String XSD_SIMPLE_CONTENT_TAG = "simpleContent"; @NonNls public static final String NO_NAMESPACE_SCHEMA_LOCATION_ATT = "noNamespaceSchemaLocation"; @NonNls public static final String SCHEMA_LOCATION_ATT = "schemaLocation"; @NonNls public static final String[] WEB_XML_URIS = {"http://java.sun.com/xml/ns/j2ee", "http://java.sun.com/xml/ns/javaee", "http://xmlns.jcp.org/xml/ns/javaee", "http://java.sun.com/dtd/web-app_2_3.dtd", "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd"}; - @NonNls public static final String FACELETS_URI = "http://java.sun.com/jsf/facelets"; @NonNls public static final String FACELETS_URI_JAVAEE_7 = "http://xmlns.jcp.org/jsf/facelets"; @NonNls public static final String[] FACELETS_URIS = {FACELETS_URI, FACELETS_URI_JAVAEE_7}; - @NonNls public static final String JSTL_FUNCTIONS_URI = "http://java.sun.com/jsp/jstl/functions"; @NonNls public static final String JSTL_FUNCTIONS_URI2 = "http://java.sun.com/jstl/functions"; @NonNls public static final String JSTL_FUNCTIONS_JAVAEE_7 = "http://xmlns.jcp.org/jsp/jstl/functions"; @NonNls public static final String[] JSTL_FUNCTIONS_URIS = {JSTL_FUNCTIONS_URI, JSTL_FUNCTIONS_URI2}; - @NonNls public static final String JSTL_FN_FACELET_URI = "com.sun.facelets.tag.jstl.fn.JstlFnLibrary"; @NonNls public static final String JSTL_CORE_FACELET_URI = "com.sun.facelets.tag.jstl.core.JstlCoreLibrary"; @NonNls public static final String TARGET_NAMESPACE_ATTR_NAME = "targetNamespace"; @@ -166,7 +146,6 @@ public class XmlUtil { @NonNls public static final String ENUMERATION_TAG_NAME = "enumeration"; @NonNls public static final String HTML4_LOOSE_URI = "http://www.w3.org/TR/html4/loose.dtd"; @NonNls public static final String WSDL_SCHEMA_URI = "http://schemas.xmlsoap.org/wsdl/"; - public static final String XHTML4_SCHEMA_LOCATION; public final static ThreadLocal<Boolean> BUILDING_DOM_STUBS = new ThreadLocal<Boolean>() { @Override @@ -174,52 +153,38 @@ public class XmlUtil { return Boolean.FALSE; } }; + private static final Logger LOG = Logger.getInstance("#com.intellij.xml.util.XmlUtil"); + @NonNls private static final String JSTL_FORMAT_URI3 = "http://java.sun.com/jstl/fmt_rt"; + @NonNls public static final String[] JSTL_FORMAT_URIS = {JSTL_FORMAT_URI, JSTL_FORMAT_URI2, JSTL_FORMAT_URI3}; @NonNls private static final String FILE = "file:"; @NonNls private static final String CLASSPATH = "classpath:/"; @NonNls private static final String URN = "urn:"; + private final static Set<String> doNotVisitTags = new HashSet<String>(Arrays.asList("annotation", "element", "attribute")); private XmlUtil() { } - static { final URL xhtml4SchemaLocationUrl = XmlUtil.class.getResource(ExternalResourceManagerEx.STANDARD_SCHEMAS + "xhtml1-transitional.xsd"); XHTML4_SCHEMA_LOCATION = VfsUtilCore.urlToPath(VfsUtilCore.toIdeaUrl(FileUtil.unquote(xhtml4SchemaLocationUrl.toExternalForm()), false)); } - @Nullable - public static String getSchemaLocation(XmlTag tag, String namespace) { - final String uri = ExternalResourceManagerEx.getInstanceEx().getResourceLocation(namespace, tag.getProject()); - if (uri != null && !uri.equals(namespace)) return uri; - - while (true) { - if (namespace.isEmpty()) { - final String attributeValue = tag.getAttributeValue("noNamespaceSchemaLocation", XML_SCHEMA_INSTANCE_URI); - if (attributeValue != null) return attributeValue; - } - else { - String schemaLocation = tag.getAttributeValue("schemaLocation", XML_SCHEMA_INSTANCE_URI); - if (schemaLocation != null) { - int start = schemaLocation.indexOf(namespace); - if (start >= 0) { - start += namespace.length(); - final StringTokenizer tokenizer = new StringTokenizer(schemaLocation.substring(start + 1)); - if (tokenizer.hasMoreTokens()) { - return tokenizer.nextToken(); - } - else { - return null; - } + public static String getSchemaLocation(XmlTag tag, final String namespace) { + while (tag != null) { + String schemaLocation = tag.getAttributeValue(SCHEMA_LOCATION_ATT, XML_SCHEMA_INSTANCE_URI); + if (schemaLocation != null) { + StringTokenizer tokenizer = new StringTokenizer(schemaLocation); + int i = 0; + while (tokenizer.hasMoreTokens()) { + String token = tokenizer.nextToken(); + if (i % 2 == 0 && namespace.equals(token) && tokenizer.hasMoreTokens()) { + return tokenizer.nextToken(); } + i++; } } - if (tag.getParent() instanceof XmlTag) { - tag = (XmlTag)tag.getParent(); - } - else { - break; - } + tag = tag.getParentTag(); } - return null; + return namespace; } @Nullable @@ -965,8 +930,6 @@ public class XmlUtil { }); } - private final static Set<String> doNotVisitTags = new HashSet<String>(Arrays.asList("annotation", "element", "attribute")); - /** * @return true if enumeration is exhaustive */ @@ -1189,31 +1152,6 @@ public class XmlUtil { return ExternalResourceManager.getInstance().getResourceLocation(s, project) != s; } - private static class MyAttributeInfo implements Comparable { - boolean myRequired = true; - String myName = null; - - MyAttributeInfo(String name) { - myName = name; - } - - MyAttributeInfo(String name, boolean flag) { - myName = name; - myRequired = flag; - } - - @Override - public int compareTo(Object o) { - if (o instanceof MyAttributeInfo) { - return myName.compareTo(((MyAttributeInfo)o).myName); - } - else if (o instanceof XmlAttribute) { - return myName.compareTo(((XmlAttribute)o).getName()); - } - return -1; - } - } - public static String generateDocumentDTD(XmlDocument doc, boolean full) { final Map<String, List<String>> tags = new LinkedHashMap<String, List<String>>(); final Map<String, List<MyAttributeInfo>> attributes = new LinkedHashMap<String, List<MyAttributeInfo>>(); @@ -1303,7 +1241,6 @@ public class XmlUtil { return name == null ? null : name.substring(name.indexOf(':') + 1); } - public static XmlFile getContainingFile(PsiElement element) { while (!(element instanceof XmlFile) && element != null) { final PsiElement context = element.getContext(); @@ -1482,4 +1419,29 @@ public class XmlUtil { @NotNull PsiElement getNodeForMessage(@NotNull T t); } + + private static class MyAttributeInfo implements Comparable { + boolean myRequired = true; + String myName = null; + + MyAttributeInfo(String name) { + myName = name; + } + + MyAttributeInfo(String name, boolean flag) { + myName = name; + myRequired = flag; + } + + @Override + public int compareTo(Object o) { + if (o instanceof MyAttributeInfo) { + return myName.compareTo(((MyAttributeInfo)o).myName); + } + else if (o instanceof XmlAttribute) { + return myName.compareTo(((XmlAttribute)o).getName()); + } + return -1; + } + } } |