| /* |
| * Copyright 2007 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.plugins.relaxNG.model.annotation; |
| |
| import com.intellij.lang.annotation.Annotation; |
| import com.intellij.lang.annotation.AnnotationHolder; |
| import com.intellij.lang.annotation.Annotator; |
| import com.intellij.lang.annotation.HighlightSeverity; |
| import com.intellij.openapi.editor.markup.GutterIconRenderer; |
| import com.intellij.psi.PsiElement; |
| import com.intellij.psi.PsiFile; |
| import com.intellij.psi.search.PsiElementProcessor; |
| import com.intellij.psi.xml.XmlFile; |
| import com.intellij.util.SmartList; |
| import com.intellij.util.xml.DomElement; |
| import com.intellij.util.xml.highlighting.DomElementAnnotationHolder; |
| import com.intellij.util.xml.highlighting.DomElementsAnnotator; |
| import org.intellij.plugins.relaxNG.model.CommonElement; |
| import org.intellij.plugins.relaxNG.model.Define; |
| import org.intellij.plugins.relaxNG.model.Grammar; |
| import org.intellij.plugins.relaxNG.model.Include; |
| import org.intellij.plugins.relaxNG.model.resolve.DefinitionResolver; |
| import org.intellij.plugins.relaxNG.model.resolve.GrammarFactory; |
| import org.intellij.plugins.relaxNG.model.resolve.RelaxIncludeIndex; |
| import org.intellij.plugins.relaxNG.xml.dom.RngDomElement; |
| import org.jetbrains.annotations.NotNull; |
| |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| /* |
| * Created by IntelliJ IDEA. |
| * User: sweinreuter |
| * Date: 04.12.2007 |
| */ |
| public final class ModelAnnotator implements Annotator, DomElementsAnnotator { |
| |
| @Override |
| public void annotate(@NotNull PsiElement psiElement, @NotNull AnnotationHolder holder) { |
| if (psiElement instanceof CommonElement) { |
| ((CommonElement)psiElement).accept(new MyAnnotator<PsiElement>(CommonAnnotationHolder.create(holder))); |
| } |
| } |
| |
| @Override |
| public void annotate(DomElement element, DomElementAnnotationHolder holder) { |
| if (element instanceof RngDomElement) { |
| ((RngDomElement)element).accept(new MyAnnotator<DomElement>(CommonAnnotationHolder.create(holder))); |
| } |
| } |
| |
| private final class MyAnnotator<T> extends CommonElement.Visitor { |
| private final CommonAnnotationHolder<T> myHolder; |
| |
| public MyAnnotator(CommonAnnotationHolder<T> holder) { |
| myHolder = holder; |
| } |
| |
| @Override |
| public void visitDefine(final Define define) { |
| final PsiElement element = define.getPsiElement(); |
| if (element != null) { |
| final XmlFile xmlFile = (XmlFile)element.getContainingFile(); |
| |
| final List<Define> result = new SmartList<Define>(); |
| final OverriddenDefineSearcher searcher = new OverriddenDefineSearcher(define, xmlFile, result); |
| |
| final PsiElementProcessor.FindElement<XmlFile> processor = new PsiElementProcessor.FindElement<XmlFile>() { |
| @Override |
| public boolean execute(@NotNull XmlFile file) { |
| final Grammar grammar = GrammarFactory.getGrammar(file); |
| if (grammar == null) return true; |
| |
| grammar.acceptChildren(searcher); |
| |
| return result.size() == 0 || super.execute(file); |
| } |
| }; |
| |
| RelaxIncludeIndex.processBackwardDependencies(xmlFile, processor); |
| |
| if (processor.isFound()) { |
| createGutterAnnotation(define, new OverriddenDefineRenderer(define)); |
| } |
| } |
| } |
| |
| @SuppressWarnings({ "unchecked" }) |
| private void createGutterAnnotation(CommonElement t, GutterIconRenderer renderer) { |
| final Annotation a = myHolder.createAnnotation((T)t, HighlightSeverity.INFORMATION, null); |
| a.setGutterIconRenderer(renderer); |
| } |
| |
| @Override |
| public void visitInclude(Include inc) { |
| final Define[] overrides = inc.getOverrides(); |
| for (Define define : overrides) { |
| final PsiFile file = inc.getInclude(); |
| if (!(file instanceof XmlFile)) continue; // |
| |
| final Grammar grammar = GrammarFactory.getGrammar((XmlFile)file); |
| if (grammar == null) continue; |
| |
| final Map<String, Set<Define>> map = DefinitionResolver.getAllVariants(grammar); |
| if (map == null) continue; |
| |
| final Set<Define> set = map.get(define.getName()); |
| if (set == null || set.size() == 0) { |
| //noinspection unchecked |
| myHolder.createAnnotation((T)define, HighlightSeverity.ERROR, "Definition doesn't override anything from " + file.getName()); |
| continue; |
| } |
| |
| final String message = "Overrides '" + define.getName() + "' in " + file.getName(); |
| createGutterAnnotation(define, new OverridingDefineRenderer(message, set)); |
| } |
| } |
| } |
| } |