update copyrights
[idea/community.git] / platform / lang-impl / src / com / intellij / codeInsight / daemon / impl / IdentifierHighlighterPass.java
1 /*
2  * Copyright 2000-2009 JetBrains s.r.o.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 package com.intellij.codeInsight.daemon.impl;
18
19 import com.intellij.codeHighlighting.TextEditorHighlightingPass;
20 import com.intellij.codeInsight.CodeInsightSettings;
21 import com.intellij.codeInsight.TargetElementUtilBase;
22 import com.intellij.codeInsight.highlighting.HighlightUsagesHandler;
23 import com.intellij.codeInsight.highlighting.HighlightUsagesHandlerBase;
24 import com.intellij.codeInsight.highlighting.ReadWriteAccessDetector;
25 import com.intellij.lang.annotation.HighlightSeverity;
26 import com.intellij.openapi.editor.Document;
27 import com.intellij.openapi.editor.Editor;
28 import com.intellij.openapi.editor.colors.EditorColors;
29 import com.intellij.openapi.editor.markup.MarkupModel;
30 import com.intellij.openapi.editor.markup.RangeHighlighter;
31 import com.intellij.openapi.progress.ProgressIndicator;
32 import com.intellij.openapi.project.Project;
33 import com.intellij.openapi.util.TextRange;
34 import com.intellij.psi.PsiElement;
35 import com.intellij.psi.PsiFile;
36 import com.intellij.psi.PsiReference;
37 import com.intellij.psi.search.LocalSearchScope;
38 import com.intellij.psi.search.searches.ReferencesSearch;
39 import com.intellij.util.Processor;
40 import com.intellij.util.containers.ContainerUtil;
41
42 import java.util.ArrayList;
43 import java.util.Collection;
44 import java.util.Collections;
45 import java.util.List;
46
47 /**
48  * @author yole
49  */
50 public class IdentifierHighlighterPass extends TextEditorHighlightingPass {
51   private final PsiFile myFile;
52   private final Editor myEditor;
53   private final Collection<TextRange> myReadAccessRanges = new ArrayList<TextRange>();
54   private final Collection<TextRange> myWriteAccessRanges = new ArrayList<TextRange>();
55   private final int myCaretOffset;
56
57   private static final HighlightInfoType ourReadHighlightInfoType = new HighlightInfoType.HighlightInfoTypeImpl(HighlightSeverity.INFORMATION, EditorColors.IDENTIFIER_UNDER_CARET_ATTRIBUTES);
58   private static final HighlightInfoType ourWriteHighlightInfoType = new HighlightInfoType.HighlightInfoTypeImpl(HighlightSeverity.INFORMATION, EditorColors.WRITE_IDENTIFIER_UNDER_CARET_ATTRIBUTES);
59
60   protected IdentifierHighlighterPass(final Project project, final PsiFile file, final Editor editor) {
61     super(project, editor.getDocument(), false);
62     myFile = file;
63     myEditor = editor;
64     myCaretOffset = myEditor.getCaretModel().getOffset();
65   }
66
67   public void doCollectInformation(final ProgressIndicator progress) {
68     if (!CodeInsightSettings.getInstance().HIGHLIGHT_IDENTIFIER_UNDER_CARET) {
69       return;
70     }
71
72     final HighlightUsagesHandlerBase handler = HighlightUsagesHandler.createCustomHandler(myEditor, myFile);
73     if (handler != null) {
74       final List targets = handler.getTargets();
75       handler.computeUsages(targets);
76       myReadAccessRanges.addAll(handler.getReadUsages());
77       myWriteAccessRanges.addAll(handler.getWriteUsages());
78       return;
79     }
80
81     final PsiElement myTarget = TargetElementUtilBase.getInstance().findTargetElement(myEditor, TargetElementUtilBase.ELEMENT_NAME_ACCEPTED | TargetElementUtilBase.REFERENCED_ELEMENT_ACCEPTED, myCaretOffset);
82     if (myTarget != null) {
83       final ReadWriteAccessDetector detector = ReadWriteAccessDetector.findDetector(myTarget);
84       ReferencesSearch.search(myTarget, new LocalSearchScope(myFile)).forEach(new Processor<PsiReference>() {
85         public boolean process(final PsiReference psiReference) {
86           final TextRange textRange = HighlightUsagesHandler.getRangeToHighlight(psiReference);
87           if (detector == null || detector.getReferenceAccess(myTarget, psiReference) == ReadWriteAccessDetector.Access.Read) {
88             myReadAccessRanges.add(textRange);
89           }
90           else {
91             myWriteAccessRanges.add(textRange);
92           }
93           return true;
94         }
95       });
96
97       final TextRange declRange = HighlightUsagesHandler.getNameIdentifierRange(myFile, myTarget);
98       if (declRange != null) {
99         if (detector != null && detector.isDeclarationWriteAccess(myTarget)) {
100           myWriteAccessRanges.add(declRange);
101         }
102         else {
103           myReadAccessRanges.add(declRange);
104         }
105       }
106     }
107   }
108
109   public void doApplyInformationToEditor() {
110     final boolean virtSpace = TargetElementUtilBase.inVirtualSpace(myEditor, myEditor.getCaretModel().getOffset());
111     final List<HighlightInfo> infos = virtSpace ? Collections.<HighlightInfo>emptyList() : getHighlights();
112     UpdateHighlightersUtil.setHighlightersToEditor(myProject, myDocument, 0, myFile.getTextLength(), infos, getId());
113   }
114
115   private List<HighlightInfo> getHighlights() {
116     if (myReadAccessRanges.isEmpty() && myWriteAccessRanges.isEmpty()) {
117       return Collections.emptyList();
118     }
119     List<HighlightInfo> result = new ArrayList<HighlightInfo>(myReadAccessRanges.size() + myWriteAccessRanges.size());
120     for (TextRange range: myReadAccessRanges) {
121       ContainerUtil.addIfNotNull(HighlightInfo.createHighlightInfo(ourReadHighlightInfoType, range, null),result);
122     }
123     for (TextRange range: myWriteAccessRanges) {
124       ContainerUtil.addIfNotNull(HighlightInfo.createHighlightInfo(ourWriteHighlightInfoType, range, null),result);
125     }
126     return result;
127   }
128
129   public static void clearMyHighlights(Document document, Project project) {
130     MarkupModel markupModel = document.getMarkupModel(project);
131     List<HighlightInfo> old = DaemonCodeAnalyzerImpl.getHighlights(document, project);
132     List<HighlightInfo> result = new ArrayList<HighlightInfo>(old == null ? Collections.<HighlightInfo>emptyList() : old);
133     for (RangeHighlighter highlighter : markupModel.getAllHighlighters()) {
134       Object tooltip = highlighter.getErrorStripeTooltip();
135       if (!(tooltip instanceof HighlightInfo)) {
136         continue;
137       }
138       HighlightInfo info = (HighlightInfo)tooltip;
139       if (info.type == ourReadHighlightInfoType || info.type == ourWriteHighlightInfoType) {
140         result.remove(info);
141         markupModel.removeHighlighter(highlighter);
142       }
143     }
144     DaemonCodeAnalyzerImpl.setHighlights(markupModel, project, result, Collections.<HighlightInfo>emptyList());
145   }
146 }