update copyright
[fedora-idea.git] / xml / impl / src / com / intellij / codeInsight / daemon / impl / analysis / XmlUnboundNsPrefixInspection.java
blob6f7aa860e47146c2b5d99dc151e16d4cda22c058
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.intellij.codeInsight.daemon.impl.analysis;
18 import com.intellij.codeHighlighting.HighlightDisplayLevel;
19 import com.intellij.codeInsight.daemon.XmlErrorMessages;
20 import com.intellij.codeInsight.daemon.impl.HighlightInfoType;
21 import com.intellij.codeInspection.ProblemHighlightType;
22 import com.intellij.codeInspection.ProblemsHolder;
23 import com.intellij.codeInspection.XmlSuppressableInspectionTool;
24 import com.intellij.lang.injection.InjectedLanguageManager;
25 import com.intellij.openapi.util.TextRange;
26 import com.intellij.psi.*;
27 import com.intellij.psi.templateLanguages.OuterLanguageElement;
28 import com.intellij.psi.xml.*;
29 import com.intellij.xml.XmlBundle;
30 import com.intellij.xml.XmlElementDescriptor;
31 import com.intellij.xml.XmlExtension;
32 import com.intellij.xml.impl.schema.AnyXmlElementDescriptor;
33 import com.intellij.xml.util.XmlTagUtil;
34 import com.intellij.xml.util.XmlUtil;
35 import org.jetbrains.annotations.NonNls;
36 import org.jetbrains.annotations.NotNull;
38 /**
39 * @author Dmitry Avdeev
41 public class XmlUnboundNsPrefixInspection extends XmlSuppressableInspectionTool {
43 @NonNls private static final String XML = "xml";
45 @NotNull
46 @Override
47 public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, final boolean isOnTheFly) {
48 return new XmlElementVisitor() {
50 private Boolean isXml;
52 private boolean isXmlFile(XmlElement element) {
53 if (isXml == null) {
54 final PsiFile file = element.getContainingFile();
55 isXml = file instanceof XmlFile && !InjectedLanguageManager.getInstance(element.getProject()).isInjectedFragment(file);
57 return isXml.booleanValue();
60 @Override
61 public void visitXmlToken(final XmlToken token) {
62 if (isXmlFile(token) && token.getTokenType() == XmlTokenType.XML_NAME) {
63 PsiElement element = token.getPrevSibling();
64 while(element instanceof PsiWhiteSpace) element = element.getPrevSibling();
66 if (element instanceof XmlToken && ((XmlToken)element).getTokenType() == XmlTokenType.XML_START_TAG_START) {
67 PsiElement parent = element.getParent();
69 if (parent instanceof XmlTag && !(token.getNextSibling() instanceof OuterLanguageElement)) {
70 XmlTag tag = (XmlTag)parent;
71 checkUnboundNamespacePrefix(tag, tag, tag.getNamespacePrefix(), token, holder);
77 @Override
78 public void visitXmlAttribute(final XmlAttribute attribute) {
79 if (!isXmlFile(attribute)) {
80 return;
82 final String namespace = attribute.getNamespace();
83 if (attribute.isNamespaceDeclaration() || XmlUtil.XML_SCHEMA_INSTANCE_URI.equals(namespace)) {
84 return;
87 XmlTag tag = attribute.getParent();
88 XmlElementDescriptor elementDescriptor = tag.getDescriptor();
89 if (elementDescriptor == null ||
90 elementDescriptor instanceof AnyXmlElementDescriptor) {
91 return;
95 final String name = attribute.getName();
97 checkUnboundNamespacePrefix(attribute, tag, XmlUtil.findPrefixByQualifiedName(name), null, holder);
102 private static void checkUnboundNamespacePrefix(final XmlElement element, final XmlTag context, String namespacePrefix, final XmlToken token,
103 final ProblemsHolder holder) {
105 if (namespacePrefix.length() == 0 && (!(element instanceof XmlTag) || !(element.getParent() instanceof XmlDocument))
106 || XML.equals(namespacePrefix)) {
107 return;
110 final String namespaceByPrefix = context.getNamespaceByPrefix(namespacePrefix);
111 if (namespaceByPrefix.length() != 0) {
112 return;
115 final XmlFile containingFile = (XmlFile)context.getContainingFile();
116 if (!HighlightLevelUtil.shouldInspect(containingFile)) return;
118 final XmlExtension extension = XmlExtension.getExtension(containingFile);
119 if (extension.isPrefixDeclared(context, namespacePrefix)) {
120 return;
123 final String localizedMessage = XmlErrorMessages.message("unbound.namespace", namespacePrefix);
125 if (namespacePrefix.length() == 0) {
126 final XmlTag tag = (XmlTag)element;
127 if (!XmlUtil.JSP_URI.equals(tag.getNamespace())) {
128 reportTagProblem(tag, localizedMessage, null, ProblemHighlightType.INFORMATION, new CreateNSDeclarationIntentionFix(context, namespacePrefix, token),
129 holder);
131 return;
134 final int prefixLength = namespacePrefix.length();
135 final TextRange range = new TextRange(0, prefixLength);
136 final HighlightInfoType infoType = extension.getHighlightInfoType(containingFile);
137 final ProblemHighlightType highlightType = infoType == HighlightInfoType.ERROR ? ProblemHighlightType.ERROR : ProblemHighlightType.LIKE_UNKNOWN_SYMBOL;
138 if (element instanceof XmlTag) {
139 final CreateNSDeclarationIntentionFix fix = new CreateNSDeclarationIntentionFix(context, namespacePrefix, token);
140 reportTagProblem(element, localizedMessage, range, highlightType, fix, holder);
141 } else {
142 holder.registerProblem(element, localizedMessage, highlightType, range);
146 private static void reportTagProblem(final XmlElement element, final String localizedMessage, final TextRange range, final ProblemHighlightType highlightType,
147 final CreateNSDeclarationIntentionFix fix,
148 final ProblemsHolder holder) {
150 XmlToken nameToken = XmlTagUtil.getStartTagNameElement((XmlTag)element);
151 if (nameToken != null) {
152 holder.registerProblem(nameToken, localizedMessage, highlightType, range, fix);
154 nameToken = XmlTagUtil.getEndTagNameElement((XmlTag)element);
155 if (nameToken != null) {
156 holder.registerProblem(nameToken, localizedMessage, highlightType, range, fix);
161 @NotNull
162 public HighlightDisplayLevel getDefaultLevel() {
163 return HighlightDisplayLevel.WARNING;
166 public boolean isEnabledByDefault() {
167 return true;
170 @NotNull
171 public String getGroupDisplayName() {
172 return XmlBundle.message("xml.inspections.group.name");
175 @NotNull
176 public String getDisplayName() {
177 return XmlBundle.message("xml.inspections.unbound.prefix");
180 @NotNull
181 @NonNls
182 public String getShortName() {
183 return "XmlUnboundNsPrefix";