IDEADEV-14701 && IDEADEV-14703
[fedora-idea.git] / dom / impl / src / com / intellij / util / xml / highlighting / DomElementsHighlightingUtil.java
blob3e44107cdb920dda1350986a275903c8851ee263
1 /*
2 * Copyright (c) 2000-2006 JetBrains s.r.o. All Rights Reserved.
3 */
5 package com.intellij.util.xml.highlighting;
7 import com.intellij.codeInsight.daemon.impl.AnnotationHolderImpl;
8 import com.intellij.codeInspection.InspectionManager;
9 import com.intellij.codeInspection.ProblemDescriptor;
10 import com.intellij.codeInspection.ProblemHighlightType;
11 import com.intellij.lang.ASTNode;
12 import com.intellij.lang.annotation.Annotation;
13 import com.intellij.lang.annotation.HighlightSeverity;
14 import com.intellij.openapi.editor.colors.CodeInsightColors;
15 import com.intellij.openapi.util.Pair;
16 import com.intellij.openapi.util.TextRange;
17 import com.intellij.openapi.util.text.StringUtil;
18 import com.intellij.psi.PsiElement;
19 import com.intellij.psi.PsiReference;
20 import com.intellij.psi.xml.XmlAttributeValue;
21 import com.intellij.psi.xml.XmlChildRole;
22 import com.intellij.psi.xml.XmlTag;
23 import com.intellij.psi.xml.XmlText;
24 import com.intellij.util.Function;
25 import com.intellij.util.SmartList;
26 import com.intellij.util.xml.DomElement;
27 import com.intellij.util.xml.GenericAttributeValue;
28 import com.intellij.util.xml.GenericValue;
29 import org.jetbrains.annotations.Nullable;
31 import java.util.Arrays;
32 import java.util.List;
34 /**
35 * User: Sergey.Vasiliev
37 public class DomElementsHighlightingUtil {
39 private static final AnnotationHolderImpl EMPTY_ANNOTATION_HOLDER = new AnnotationHolderImpl() {
40 public boolean add(final Annotation annotation) {
41 return false;
45 private DomElementsHighlightingUtil() {
48 public static List<ProblemDescriptor> createProblemDescriptors(final InspectionManager manager,
49 final DomElementProblemDescriptor problemDescriptor) {
50 final ProblemHighlightType type = getProblemHighlightType(problemDescriptor);
51 return createProblemDescriptors(problemDescriptor, new Function<Pair<TextRange, PsiElement>, ProblemDescriptor>() {
52 public ProblemDescriptor fun(final Pair<TextRange, PsiElement> s) {
53 return manager
54 .createProblemDescriptor(s.second, s.first, problemDescriptor.getDescriptionTemplate(), type, problemDescriptor.getFixes());
56 });
59 private static ProblemHighlightType getProblemHighlightType(final DomElementProblemDescriptor problemDescriptor) {
60 if (problemDescriptor instanceof DomElementResolveProblemDescriptor) {
61 final TextRange range = ((DomElementResolveProblemDescriptor)problemDescriptor).getPsiReference().getRangeInElement();
62 if (range.getStartOffset() != range.getEndOffset()) {
63 return ProblemHighlightType.LIKE_UNKNOWN_SYMBOL;
66 return ProblemHighlightType.GENERIC_ERROR_OR_WARNING;
69 public static List<Annotation> createAnnotations(final DomElementProblemDescriptor problemDescriptor) {
71 return createProblemDescriptors(problemDescriptor, new Function<Pair<TextRange, PsiElement>, Annotation>() {
72 public Annotation fun(final Pair<TextRange, PsiElement> s) {
73 String text = problemDescriptor.getDescriptionTemplate();
74 if (StringUtil.isEmpty(text)) text = null;
75 final HighlightSeverity severity = problemDescriptor.getHighlightSeverity();
76 final AnnotationHolderImpl holder = EMPTY_ANNOTATION_HOLDER;
77 TextRange range = s.first;
78 if (text == null) range = TextRange.from(range.getStartOffset(), 0);
79 range = range.shiftRight(s.second.getTextRange().getStartOffset());
80 final Annotation annotation = createAnnotation(severity, holder, range, text);
81 if (problemDescriptor instanceof DomElementResolveProblemDescriptor) {
82 annotation.setTextAttributes(CodeInsightColors.WRONG_REFERENCES_ATTRIBUTES);
84 return annotation;
86 });
89 private static Annotation createAnnotation(final HighlightSeverity severity,
90 final AnnotationHolderImpl holder,
91 final TextRange range,
92 final String text) {
93 if (severity.compareTo(HighlightSeverity.ERROR) >= 0) return holder.createErrorAnnotation(range, text);
94 if (severity.compareTo(HighlightSeverity.WARNING) >= 0) return holder.createWarningAnnotation(range, text);
95 if (severity.compareTo(HighlightSeverity.INFO) >= 0) return holder.createInformationAnnotation(range, text);
96 return holder.createInfoAnnotation(range, text);
99 private static <T> List<T> createProblemDescriptors(final DomElementProblemDescriptor problemDescriptor,
100 final Function<Pair<TextRange, PsiElement>, T> creator) {
101 final List<T> descriptors = new SmartList<T>();
103 if (problemDescriptor instanceof DomElementResolveProblemDescriptor) {
104 final PsiReference reference = ((DomElementResolveProblemDescriptor)problemDescriptor).getPsiReference();
105 final PsiElement element = reference.getElement();
106 final TextRange referenceRange = reference.getRangeInElement();
107 final TextRange errorRange;
108 if (referenceRange.getStartOffset() == referenceRange.getEndOffset()) {
109 if (element instanceof XmlAttributeValue) {
110 errorRange = TextRange.from(referenceRange.getStartOffset() - 1, 2);
112 else {
113 errorRange = TextRange.from(referenceRange.getStartOffset(), 1);
116 else {
117 errorRange = referenceRange;
119 descriptors.add(creator.fun(Pair.create(errorRange, element)));
120 return descriptors;
123 final DomElement domElement = problemDescriptor.getDomElement();
124 final PsiElement psiElement = getPsiElement(domElement);
125 final DomElementProblemDescriptor.HighlightingType highlightingType = problemDescriptor.getHighlightingType();
127 if (highlightingType == DomElementProblemDescriptor.HighlightingType.WHOLE_ELEMENT) {
128 if (psiElement instanceof XmlAttributeValue) {
129 final PsiElement attr = psiElement.getParent();
130 descriptors.add(creator.fun(Pair.create(new TextRange(0, attr.getTextLength()), attr)));
132 else {
133 final XmlTag tag = (XmlTag)(psiElement instanceof XmlTag ? psiElement : psiElement.getParent());
134 descriptors.add(creator.fun(Pair.create(new TextRange(0, tag.getTextLength()), (PsiElement)tag)));
136 return descriptors;
139 if (psiElement != null && StringUtil.isNotEmpty(psiElement.getText())) {
140 if (psiElement instanceof XmlTag) {
141 final XmlTag tag = (XmlTag)psiElement;
142 switch (highlightingType) {
143 case WHOLE_ELEMENT:
144 descriptors.add(creator.fun(Pair.create(new TextRange(0, tag.getTextLength()), (PsiElement)tag)));
145 break;
146 case START_TAG_NAME:
147 addDescriptionsToTagEnds(tag, descriptors, creator);
148 break;
151 return descriptors;
155 TextRange textRange = problemDescriptor.getTextRange();
157 if (textRange == null) {
158 int start = 0;
159 int length = psiElement.getTextRange().getLength();
160 if (psiElement instanceof XmlAttributeValue) {
161 String value = ((XmlAttributeValue)psiElement).getValue();
162 if (StringUtil.isNotEmpty(value)) {
163 start = psiElement.getText().indexOf(value);
164 length = value.length();
167 textRange = TextRange.from(start, length);
169 return Arrays.asList(creator.fun(Pair.create(textRange, psiElement)));
172 final XmlTag tag = getParentXmlTag(domElement);
173 if (tag != null) {
174 addDescriptionsToTagEnds(tag, descriptors, creator);
176 return descriptors;
179 private static <T> void addDescriptionsToTagEnds(final XmlTag tag,
180 final List<T> descriptors,
181 Function<Pair<TextRange, PsiElement>, T> creator) {
182 final ASTNode node = tag.getNode();
183 assert node != null;
184 final ASTNode startNode = XmlChildRole.START_TAG_NAME_FINDER.findChild(node);
186 final int startOffset = tag.getTextRange().getStartOffset();
187 assert startNode != null;
188 descriptors.add(creator.fun(Pair.create(startNode.getTextRange().shiftRight(-startOffset), (PsiElement)tag)));
191 @Nullable
192 private static PsiElement getPsiElement(final DomElement domElement) {
193 if (domElement instanceof GenericAttributeValue) {
194 final GenericAttributeValue attributeValue = (GenericAttributeValue)domElement;
195 final XmlAttributeValue value = attributeValue.getXmlAttributeValue();
196 return value != null && StringUtil.isNotEmpty(value.getText()) ? value : attributeValue.getXmlElement();
198 final XmlTag tag = domElement.getXmlTag();
199 if (domElement instanceof GenericValue && tag != null) {
200 final XmlText[] textElements = tag.getValue().getTextElements();
201 if (textElements.length > 0) {
202 return textElements[0];
206 return tag;
209 @Nullable
210 private static XmlTag getParentXmlTag(final DomElement domElement) {
211 DomElement parent = domElement.getParent();
212 while (parent != null) {
213 if (parent.getXmlTag() != null) return parent.getXmlTag();
214 parent = parent.getParent();
216 return null;