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.
17 package com
.intellij
.codeInspection
.ex
;
19 import com
.intellij
.codeInspection
.*;
20 import com
.intellij
.openapi
.application
.ApplicationManager
;
21 import com
.intellij
.openapi
.diagnostic
.Logger
;
22 import com
.intellij
.openapi
.editor
.Document
;
23 import com
.intellij
.openapi
.editor
.colors
.TextAttributesKey
;
24 import com
.intellij
.openapi
.project
.Project
;
25 import com
.intellij
.openapi
.util
.TextRange
;
26 import com
.intellij
.pom
.Navigatable
;
27 import com
.intellij
.psi
.*;
28 import com
.intellij
.psi
.util
.PsiTreeUtil
;
29 import com
.intellij
.psi
.util
.PsiUtilBase
;
30 import org
.jetbrains
.annotations
.NotNull
;
31 import org
.jetbrains
.annotations
.Nullable
;
36 public class ProblemDescriptorImpl
extends CommonProblemDescriptorImpl
implements ProblemDescriptor
{
37 private static final Logger LOG
= Logger
.getInstance("#com.intellij.codeInspection.ex.ProblemDescriptorImpl");
39 @NotNull private final SmartPsiElementPointer myStartSmartPointer
;
40 @Nullable private final SmartPsiElementPointer myEndSmartPointer
;
43 private final ProblemHighlightType myHighlightType
;
44 private Navigatable myNavigatable
;
45 private final boolean myAfterEndOfLine
;
46 private final TextRange myTextRangeInElement
;
47 private final boolean myShowTooltip
;
48 private final HintAction myHintAction
;
49 private TextAttributesKey myEnforcedTextAttributes
;
51 public ProblemDescriptorImpl(@NotNull PsiElement startElement
, @NotNull PsiElement endElement
, String descriptionTemplate
, LocalQuickFix
[] fixes
,
52 ProblemHighlightType highlightType
,
53 boolean isAfterEndOfLine
,
54 final TextRange rangeInElement
,
56 this(startElement
, endElement
, descriptionTemplate
, fixes
, highlightType
, isAfterEndOfLine
, rangeInElement
, null, onTheFly
);
59 public ProblemDescriptorImpl(@NotNull PsiElement startElement
, @NotNull PsiElement endElement
, String descriptionTemplate
, LocalQuickFix
[] fixes
,
60 ProblemHighlightType highlightType
,
61 boolean isAfterEndOfLine
,
62 final TextRange rangeInElement
,
63 @Nullable HintAction hintAction
,
65 this(startElement
, endElement
, descriptionTemplate
, fixes
, highlightType
, isAfterEndOfLine
, rangeInElement
, true, hintAction
, onTheFly
);
68 public ProblemDescriptorImpl(@NotNull PsiElement startElement
, @NotNull PsiElement endElement
, String descriptionTemplate
, LocalQuickFix
[] fixes
,
69 ProblemHighlightType highlightType
,
70 boolean isAfterEndOfLine
,
71 final TextRange rangeInElement
,
72 final boolean tooltip
,
73 @Nullable HintAction hintAction
,
76 super(fixes
, descriptionTemplate
);
77 myShowTooltip
= tooltip
;
78 myHintAction
= hintAction
;
79 LOG
.assertTrue(startElement
.isValid(), startElement
);
80 LOG
.assertTrue(startElement
== endElement
|| endElement
.isValid(), endElement
);
81 assertPhysical(startElement
);
82 if (startElement
!= endElement
) assertPhysical(endElement
);
84 if (startElement
.getTextRange().getStartOffset() >= endElement
.getTextRange().getEndOffset()) {
85 if (!(startElement
instanceof PsiFile
&& endElement
instanceof PsiFile
)) {
86 LOG
.error("Empty PSI elements should not be passed to createDescriptor. Start: " + startElement
+ ", end: " + endElement
);
90 myHighlightType
= highlightType
;
91 final Project project
= startElement
.getProject();
92 final boolean useLazy
= !onTheFly
|| ApplicationManager
.getApplication().isHeadlessEnvironment();
93 final SmartPointerManager manager
= SmartPointerManager
.getInstance(project
);
94 myStartSmartPointer
= useLazy? manager
.createLazyPointer(startElement
) : manager
.createSmartPsiElementPointer(startElement
);
95 myEndSmartPointer
= startElement
== endElement ?
null : useLazy ? manager
.createLazyPointer(endElement
) : manager
.createSmartPsiElementPointer(endElement
);
97 myAfterEndOfLine
= isAfterEndOfLine
;
98 myTextRangeInElement
= rangeInElement
;
101 protected void assertPhysical(final PsiElement element
) {
102 if (!element
.isPhysical()) {
103 LOG
.error("Non-physical PsiElement. Physical element is required to be able to anchor the problem in the source tree: " +
104 element
+ "; file: " + element
.getContainingFile());
108 public PsiElement
getPsiElement() {
109 PsiElement startElement
= getStartElement();
110 if (myEndSmartPointer
== null) {
113 PsiElement endElement
= getEndElement();
114 if (startElement
== endElement
) {
117 if (startElement
== null || endElement
== null) return null;
118 return PsiTreeUtil
.findCommonParent(startElement
, endElement
);
121 public PsiElement
getStartElement() {
122 return myStartSmartPointer
.getElement();
125 public PsiElement
getEndElement() {
126 return myEndSmartPointer
== null ?
getStartElement() : myEndSmartPointer
.getElement();
129 public int getLineNumber() {
130 PsiElement psiElement
= getPsiElement();
131 if (psiElement
== null) return -1;
132 if (!psiElement
.isValid()) return -1;
133 LOG
.assertTrue(psiElement
.isPhysical());
134 PsiFile containingFile
= psiElement
.getContainingFile();
135 PsiElement containingFileContext
= containingFile
.getContext();
136 if (containingFileContext
!= null) {
137 containingFile
= containingFileContext
.getContainingFile();
139 Document document
= PsiDocumentManager
.getInstance(psiElement
.getProject()).getDocument(containingFile
);
140 if (document
== null) return -1;
141 TextRange textRange
= getTextRange();
142 if (textRange
== null) return -1;
143 if (containingFileContext
!= null) {
144 textRange
= textRange
.shiftRight(PsiUtilBase
.findInjectedElementOffsetInRealDocument(psiElement
));
146 return document
.getLineNumber(textRange
.getStartOffset()) + 1;
149 public ProblemHighlightType
getHighlightType() {
150 return myHighlightType
;
153 public boolean isAfterEndOfLine() {
154 return myAfterEndOfLine
;
157 public void setTextAttributes(TextAttributesKey key
) {
158 myEnforcedTextAttributes
= key
;
161 public TextAttributesKey
getEnforcedTextAttributes() {
162 return myEnforcedTextAttributes
;
165 public TextRange
getTextRangeForNavigation() {
166 TextRange textRange
= getTextRange();
167 if (textRange
== null) return null;
168 return textRange
.shiftRight(PsiUtilBase
.findInjectedElementOffsetInRealDocument(getPsiElement()));
171 public TextRange
getTextRange() {
172 PsiElement startElement
= getStartElement();
173 PsiElement endElement
= myEndSmartPointer
== null ? startElement
: getEndElement();
174 if (startElement
== null || endElement
== null) {
178 TextRange textRange
= startElement
.getTextRange();
179 if (startElement
== endElement
) {
180 if (isAfterEndOfLine()) return new TextRange(textRange
.getEndOffset(), textRange
.getEndOffset());
181 if (myTextRangeInElement
!= null) {
182 return new TextRange(textRange
.getStartOffset() + myTextRangeInElement
.getStartOffset(),
183 textRange
.getStartOffset() + myTextRangeInElement
.getEndOffset());
187 return new TextRange(textRange
.getStartOffset(), endElement
.getTextRange().getEndOffset());
190 public Navigatable
getNavigatable() {
191 return myNavigatable
;
194 public void setNavigatable(final Navigatable navigatable
) {
195 myNavigatable
= navigatable
;
198 public HintAction
getHintAction() {
202 public boolean showTooltip() {
203 return myShowTooltip
;