/* * Copyright 2005 Sascha Weinreuter * * 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 org.intellij.lang.xpath.validation.inspections; import com.intellij.codeInspection.InspectionManager; import com.intellij.codeInspection.LocalQuickFix; import com.intellij.codeInspection.ProblemHighlightType; import com.intellij.lang.Language; import com.intellij.psi.xml.XmlElement; import org.intellij.lang.xpath.XPathFileType; import org.intellij.lang.xpath.context.ContextProvider; import org.intellij.lang.xpath.context.NamespaceContext; import org.intellij.lang.xpath.psi.PrefixedName; import org.intellij.lang.xpath.psi.XPathNodeTest; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.xml.namespace.QName; import java.text.MessageFormat; import java.util.Set; public class CheckNodeTest extends XPathInspection { @NonNls private static final String SHORT_NAME = "CheckNodeTest"; protected Visitor createVisitor(InspectionManager manager, boolean isOnTheFly) { return new MyVisitor(manager, isOnTheFly); } @NotNull public String getDisplayName() { return "Check Node Test"; } @NotNull @NonNls public String getShortName() { return SHORT_NAME; } public boolean isEnabledByDefault() { return true; } protected boolean acceptsLanguage(Language language) { return language == XPathFileType.XPATH.getLanguage() || language == XPathFileType.XPATH2.getLanguage(); } final static class MyVisitor extends Visitor { MyVisitor(InspectionManager manager, boolean isOnTheFly) { super(manager, isOnTheFly); } protected void checkNodeTest(XPathNodeTest nodeTest) { final ContextProvider contextProvider = ContextProvider.getContextProvider(nodeTest.getContainingFile()); final XmlElement contextNode = contextProvider.getContextElement(); final NamespaceContext namespaceContext = contextProvider.getNamespaceContext(); if (namespaceContext == null) return; if (nodeTest.isNameTest() && contextNode != null) { final PrefixedName prefixedName = nodeTest.getQName(); assert prefixedName != null; if (!"*".equals(prefixedName.getLocalName()) && !"*".equals(prefixedName.getPrefix())) { boolean found; if (nodeTest.getPrincipalType() == XPathNodeTest.PrincipalType.ELEMENT) { final Set<QName> elementNames = contextProvider.getElements(true); if (elementNames != null) { found = false; for (QName pair : elementNames) { if (matches(nodeTest.getQName(), pair, namespaceContext, contextNode, true)) { found = true; break; } } if (!found) { registerProblem(contextProvider, prefixedName, nodeTest, "element"); } } } else if (nodeTest.getPrincipalType() == XPathNodeTest.PrincipalType.ATTRIBUTE) { final Set<QName> attributeNames = contextProvider.getAttributes(true); if (attributeNames != null) { found = false; for (QName pair : attributeNames) { if (matches(nodeTest.getQName(), pair, namespaceContext, contextNode, false)) { found = true; break; } } if (!found) { registerProblem(contextProvider, prefixedName, nodeTest, "attribute"); } } } } } } private void registerProblem(ContextProvider contextProvider, PrefixedName prefixedName, XPathNodeTest nodeTest, String type) { final QName qName = contextProvider.getQName(prefixedName, nodeTest); final String name; if (qName != null) { final String pattern; if (!"".equals(qName.getNamespaceURI())) { pattern = "''<b>{0}</b>'' (<i>{1}</i>)"; } else { pattern = "''<b>{0}</b>''"; } name = MessageFormat.format(pattern, qName.getLocalPart(), qName.getNamespaceURI()); } else { name = MessageFormat.format("''<b>{0}</b>''", prefixedName.getLocalName()); } final LocalQuickFix[] fixes = contextProvider.getQuickFixFactory().createUnknownNodeTestFixes(nodeTest); addProblem(myManager.createProblemDescriptor(nodeTest, "<html>Unknown " + type + " name " + name + "</html>", myOnTheFly, fixes, ProblemHighlightType.GENERIC_ERROR_OR_WARNING)); } private static boolean matches(@Nullable PrefixedName prefixedName, QName element, NamespaceContext namespaceContext, XmlElement context, boolean allowDefaultNamespace) { if (prefixedName == null) return false; boolean b = prefixedName.getLocalName().equals(element.getLocalPart()) || "*".equals(element.getLocalPart()); final String prefix = prefixedName.getPrefix(); if (prefix != null) { if (!"*".equals(prefix)) { final String namespaceURI = namespaceContext.getNamespaceURI(prefix, context); b = b && element.getNamespaceURI().equals(namespaceURI); } } else if (allowDefaultNamespace) { final String namespaceURI = namespaceContext.getDefaultNamespace(context); b = b && (element.getNamespaceURI().equals(namespaceURI) || (element.getNamespaceURI().length() == 0 && namespaceURI == null)); } else { b = b && element.getNamespaceURI().length() == 0; } return b; } } }