2 * Copyright 2000-2015 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;
19 import com.intellij.BundleBase;
20 import com.intellij.codeInsight.CodeInsightBundle;
21 import com.intellij.codeInsight.daemon.EmptyResolveMessageProvider;
22 import com.intellij.lang.injection.InjectedLanguageManager;
23 import com.intellij.openapi.diagnostic.Logger;
24 import com.intellij.openapi.project.Project;
25 import com.intellij.openapi.util.TextRange;
26 import com.intellij.openapi.util.io.FileUtil;
27 import com.intellij.openapi.vfs.VirtualFile;
28 import com.intellij.psi.ExternallyDefinedPsiElement;
29 import com.intellij.psi.PsiElement;
30 import com.intellij.psi.PsiFile;
31 import com.intellij.psi.PsiReference;
32 import com.intellij.psi.util.PsiTreeUtil;
33 import com.intellij.xml.util.XmlStringUtil;
34 import org.jetbrains.annotations.Nls;
35 import org.jetbrains.annotations.NotNull;
36 import org.jetbrains.annotations.Nullable;
38 import java.util.ArrayList;
39 import java.util.List;
44 public class ProblemsHolder {
45 private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.ProblemsHolder");
46 private final InspectionManager myManager;
47 private final PsiFile myFile;
48 private final boolean myOnTheFly;
49 private final List<ProblemDescriptor> myProblems = new ArrayList<ProblemDescriptor>();
51 public ProblemsHolder(@NotNull InspectionManager manager, @NotNull PsiFile file, boolean onTheFly) {
54 myOnTheFly = onTheFly;
57 public void registerProblem(@NotNull PsiElement psiElement, @NotNull @Nls(capitalization = Nls.Capitalization.Sentence) String descriptionTemplate, LocalQuickFix... fixes) {
58 registerProblem(psiElement, descriptionTemplate, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, fixes);
61 public void registerProblem(@NotNull PsiElement psiElement,
62 @NotNull @Nls(capitalization = Nls.Capitalization.Sentence) String descriptionTemplate,
63 ProblemHighlightType highlightType,
64 LocalQuickFix... fixes) {
65 registerProblem(myManager.createProblemDescriptor(psiElement, descriptionTemplate, myOnTheFly, fixes, highlightType));
68 public void registerProblem(@NotNull ProblemDescriptor problemDescriptor) {
69 PsiElement element = problemDescriptor.getPsiElement();
70 if (element != null && !isInPsiFile(element)) {
71 ExternallyDefinedPsiElement external = PsiTreeUtil.getParentOfType(element, ExternallyDefinedPsiElement.class, false);
72 if (external != null) {
73 PsiElement newTarget = external.getProblemTarget();
74 if (newTarget != null) {
75 redirectProblem(problemDescriptor, newTarget);
80 PsiFile containingFile = element.getContainingFile();
81 PsiElement context = InjectedLanguageManager.getInstance(containingFile.getProject()).getInjectionHost(containingFile);
82 PsiElement myContext = InjectedLanguageManager.getInstance(myFile.getProject()).getInjectionHost(myFile);
83 LOG.error("Reported element " + element + " is not from the file '" + myFile + "' the inspection was invoked for. Message: '" + problemDescriptor.getDescriptionTemplate()+"'.\n" +
84 "Element' containing file: "+ containingFile +"; context: "+(context == null ? null : context.getContainingFile())+"\n"
85 +"Inspection invoked for file: "+ myFile +"; context: "+(myContext == null ? null : myContext.getContainingFile())+"\n"
89 myProblems.add(problemDescriptor);
92 private boolean isInPsiFile(@NotNull PsiElement element) {
93 PsiFile file = element.getContainingFile();
94 return myFile.getViewProvider() == file.getViewProvider();
97 private void redirectProblem(@NotNull final ProblemDescriptor problem, @NotNull final PsiElement target) {
98 final PsiElement original = problem.getPsiElement();
99 final VirtualFile vFile = original.getContainingFile().getVirtualFile();
100 assert vFile != null;
101 final String path = FileUtil.toSystemIndependentName(vFile.getPath());
103 String description = XmlStringUtil.stripHtml(problem.getDescriptionTemplate());
105 final String template =
106 InspectionsBundle.message("inspection.redirect.template",
107 description, path, original.getTextRange().getStartOffset(), vFile.getName());
110 final InspectionManager manager = InspectionManager.getInstance(original.getProject());
111 final ProblemDescriptor newProblem =
112 manager.createProblemDescriptor(target, template, (LocalQuickFix)null, problem.getHighlightType(), isOnTheFly());
113 registerProblem(newProblem);
116 public void registerProblem(@NotNull PsiReference reference, String descriptionTemplate, ProblemHighlightType highlightType) {
117 LocalQuickFix[] fixes = null;
118 if (reference instanceof LocalQuickFixProvider) {
119 fixes = ((LocalQuickFixProvider)reference).getQuickFixes();
121 registerProblemForReference(reference, highlightType, descriptionTemplate, fixes);
124 public void registerProblemForReference(@NotNull PsiReference reference,
125 ProblemHighlightType highlightType,
126 String descriptionTemplate,
127 LocalQuickFix... fixes) {
128 ProblemDescriptor descriptor = myManager.createProblemDescriptor(reference.getElement(), reference.getRangeInElement(), descriptionTemplate, highlightType,
130 registerProblem(descriptor);
133 public void registerProblem(@NotNull PsiReference reference) {
134 registerProblem(reference, unresolvedReferenceMessage(reference), ProblemHighlightType.LIKE_UNKNOWN_SYMBOL);
137 public static String unresolvedReferenceMessage(PsiReference reference) {
139 if (reference instanceof EmptyResolveMessageProvider) {
140 String pattern = ((EmptyResolveMessageProvider)reference).getUnresolvedMessagePattern();
142 message = BundleBase.format(pattern, reference.getCanonicalText()); // avoid double formatting
144 catch (IllegalArgumentException ex) {
145 // unresolvedMessage provided by third-party reference contains wrong format string (e.g. {}), tolerate it
151 message = CodeInsightBundle.message("error.cannot.resolve.default.message", reference.getCanonicalText());
157 * Creates highlighter for the specified place in the file.
158 * @param psiElement The highlighter will be created at the text range od this element. This psiElement must be in the current file.
159 * @param message Message for this highlighter. Will also serve as a tooltip.
160 * @param highlightType The level of highlighter.
161 * @param rangeInElement The (sub)range (must be inside (0..psiElement.getTextRange().getLength()) to create highlighter in.
162 * If you want to highlight only part of the supplied psiElement. Pass null otherwise.
163 * @param fixes (Optional) fixes to appear for this highlighter.
165 public void registerProblem(@NotNull final PsiElement psiElement,
166 @NotNull final String message,
167 final ProblemHighlightType highlightType,
168 @Nullable TextRange rangeInElement,
169 final LocalQuickFix... fixes) {
171 final ProblemDescriptor descriptor = myManager.createProblemDescriptor(psiElement, rangeInElement, message, highlightType, myOnTheFly,
173 registerProblem(descriptor);
176 public void registerProblem(@NotNull final PsiElement psiElement,
177 final TextRange rangeInElement,
178 @NotNull final String message,
179 final LocalQuickFix... fixes) {
180 final ProblemDescriptor descriptor = myManager.createProblemDescriptor(psiElement, rangeInElement, message, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, myOnTheFly, fixes);
181 registerProblem(descriptor);
185 public List<ProblemDescriptor> getResults() {
190 public ProblemDescriptor[] getResultsArray() {
191 final List<ProblemDescriptor> problems = getResults();
192 return problems.toArray(new ProblemDescriptor[problems.size()]);
196 public final InspectionManager getManager() {
200 public boolean hasResults() {
201 return !myProblems.isEmpty();
204 public int getResultCount() {
205 return myProblems.size();
208 public boolean isOnTheFly() {
213 public PsiFile getFile() {
218 public final Project getProject() {
219 return myManager.getProject();