65db982c6e7ffdd01c4d6ffb2d914a08bd4803f6
[fedora-idea.git] / java / java-impl / src / com / intellij / codeInspection / javaDoc / JavaDocLocalInspection.java
blob65db982c6e7ffdd01c4d6ffb2d914a08bd4803f6
1 /*
2 * Copyright (c) 2005 Jet Brains. All Rights Reserved.
3 */
4 package com.intellij.codeInspection.javaDoc;
6 import com.intellij.ExtensionPoints;
7 import com.intellij.codeInsight.CodeInsightUtil;
8 import com.intellij.codeInsight.daemon.HighlightDisplayKey;
9 import com.intellij.codeInsight.daemon.QuickFixBundle;
10 import com.intellij.codeInspection.*;
11 import com.intellij.codeInspection.ex.BaseLocalInspectionTool;
12 import com.intellij.codeInspection.reference.RefJavaUtil;
13 import com.intellij.lang.ASTNode;
14 import com.intellij.openapi.diagnostic.Logger;
15 import com.intellij.openapi.editor.Editor;
16 import com.intellij.openapi.editor.ScrollType;
17 import com.intellij.openapi.extensions.ExtensionPoint;
18 import com.intellij.openapi.extensions.Extensions;
19 import com.intellij.openapi.fileEditor.FileEditorManager;
20 import com.intellij.openapi.project.Project;
21 import com.intellij.openapi.util.*;
22 import com.intellij.profile.codeInspection.InspectionProfileManager;
23 import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
24 import com.intellij.psi.*;
25 import com.intellij.psi.impl.source.javadoc.PsiDocParamRef;
26 import com.intellij.psi.impl.source.jsp.jspJava.JspClass;
27 import com.intellij.psi.impl.source.jsp.jspJava.JspHolderMethod;
28 import com.intellij.psi.javadoc.*;
29 import com.intellij.psi.util.InheritanceUtil;
30 import com.intellij.psi.util.PsiTreeUtil;
31 import com.intellij.ui.DocumentAdapter;
32 import com.intellij.ui.FieldPanel;
33 import com.intellij.ui.IdeBorderFactory;
34 import com.intellij.util.IJSwingUtilities;
35 import com.intellij.util.IncorrectOperationException;
36 import com.intellij.util.ui.UIUtil;
37 import org.jdom.Element;
38 import org.jetbrains.annotations.NonNls;
39 import org.jetbrains.annotations.NotNull;
40 import org.jetbrains.annotations.Nullable;
42 import javax.swing.*;
43 import javax.swing.event.ChangeEvent;
44 import javax.swing.event.ChangeListener;
45 import javax.swing.event.DocumentEvent;
46 import javax.swing.text.BadLocationException;
47 import javax.swing.text.Document;
48 import java.awt.*;
49 import java.awt.event.ActionEvent;
50 import java.awt.event.ActionListener;
51 import java.util.*;
53 public class JavaDocLocalInspection extends BaseLocalInspectionTool {
54 private static final String REQUIRED_JAVADOC_IS_ABSENT = InspectionsBundle.message("inspection.javadoc.problem.descriptor");
56 @NonNls private static final String NONE = "none";
57 @NonNls private static final String PUBLIC = "public";
58 @NonNls private static final String PROTECTED = "protected";
59 @NonNls private static final String PACKAGE_LOCAL = "package";
60 @NonNls private static final String PRIVATE = "private";
61 @NonNls private static final Set<String> ourUniqueTags = new HashSet<String>();
62 @NonNls public static final String SHORT_NAME = "JavaDoc";
64 static {
65 ourUniqueTags.add("return");
66 ourUniqueTags.add("deprecated");
67 ourUniqueTags.add("serial");
68 ourUniqueTags.add("serialData");
72 public static class Options implements JDOMExternalizable {
73 @NonNls public String ACCESS_JAVADOC_REQUIRED_FOR = NONE;
74 @NonNls public String REQUIRED_TAGS = "";
76 public Options() {
79 public Options(String ACCESS_JAVADOC_REQUIRED_FOR, String REQUIRED_TAGS) {
80 this.ACCESS_JAVADOC_REQUIRED_FOR = ACCESS_JAVADOC_REQUIRED_FOR;
81 this.REQUIRED_TAGS = REQUIRED_TAGS;
84 public void readExternal(Element element) throws InvalidDataException {
85 DefaultJDOMExternalizer.readExternal(this, element);
88 public void writeExternal(Element element) throws WriteExternalException {
89 DefaultJDOMExternalizer.writeExternal(this, element);
93 @NonNls public Options TOP_LEVEL_CLASS_OPTIONS = new Options("none", "");
94 @NonNls public Options INNER_CLASS_OPTIONS = new Options("none", "");
95 @NonNls public Options METHOD_OPTIONS = new Options("none", "@return@param@throws or @exception");
96 @NonNls public Options FIELD_OPTIONS = new Options("none", "");
97 public boolean IGNORE_DEPRECATED = false;
98 public boolean IGNORE_JAVADOC_PERIOD = true;
99 public boolean IGNORE_DUPLICATED_THROWS = false;
100 public String myAdditionalJavadocTags = "";
102 private static final Logger LOG = Logger.getInstance("com.intellij.codeInspection.javaDoc.JavaDocLocalInspection");
104 private class OptionsPanel extends JPanel {
105 private JPanel createOptionsPanel(String[] modifiers, String[] tags, Options options) {
106 JPanel pane = new JPanel(new GridLayout(1, tags == null ? 1 : 2));
108 pane.add(createScopePanel(modifiers, options));
109 if (tags != null) {
110 pane.add(createTagsPanel(tags, options));
113 pane.validate();
115 return pane;
118 private JPanel createTagsPanel(String[] tags, Options options) {
119 JPanel panel = new JPanel(new GridBagLayout());
120 panel.setBorder(BorderFactory.createCompoundBorder(IdeBorderFactory.createTitledBorder(InspectionsBundle.message("inspection.javadoc.required.tags.option.title")),
121 BorderFactory.createEmptyBorder(0, 3, 3, 3)));
123 GridBagConstraints gc = new GridBagConstraints();
124 gc.weightx = 1;
125 gc.weighty = 0;
126 gc.fill = GridBagConstraints.HORIZONTAL;
127 gc.anchor = GridBagConstraints.NORTHWEST;
130 for (int i = 0; i < tags.length; i++) {
131 JCheckBox box = new JCheckBox(tags[i]);
132 gc.gridy = i;
133 if (i == tags.length - 1) gc.weighty = 1;
134 panel.add(box, gc);
135 box.setSelected(isTagRequired(options, tags[i]));
136 box.addChangeListener(new MyChangeListener(box, options, tags[i]));
139 return panel;
142 private class MyChangeListener implements ChangeListener {
143 private final JCheckBox myCheckBox;
144 private final Options myOptions;
145 private final String myTagName;
147 public MyChangeListener(JCheckBox checkBox, Options options, String tagName) {
148 myCheckBox = checkBox;
149 myOptions = options;
150 myTagName = tagName;
153 public void stateChanged(ChangeEvent e) {
154 if (myCheckBox.isSelected()) {
155 if (!isTagRequired(myOptions,myTagName)) {
156 myOptions.REQUIRED_TAGS += myTagName;
159 else {
160 myOptions.REQUIRED_TAGS = myOptions.REQUIRED_TAGS.replaceAll(myTagName, "");
165 private JPanel createScopePanel(final String[] modifiers, final Options options) {
166 JPanel panel = new JPanel(new BorderLayout());
167 panel.setBorder(BorderFactory.createCompoundBorder(IdeBorderFactory.createTitledBorder(InspectionsBundle.message("inspection.scope.for.title")),
168 BorderFactory.createEmptyBorder(0, 3, 3, 3)));
170 final Hashtable<Integer, JLabel> sliderLabels = new Hashtable<Integer, JLabel>();
171 for (int i = 0; i < modifiers.length; i++) {
172 sliderLabels.put(i + 1, new JLabel(modifiers[i]));
175 final JSlider slider = new JSlider(SwingConstants.VERTICAL, 1, modifiers.length, 1);
177 slider.setLabelTable(sliderLabels);
178 slider.putClientProperty(UIUtil.JSLIDER_ISFILLED, Boolean.TRUE);
179 slider.setPreferredSize(new Dimension(80, 50));
180 slider.setPaintLabels(true);
181 slider.setSnapToTicks(true);
182 slider.addChangeListener(new ChangeListener() {
183 public void stateChanged(ChangeEvent e) {
184 int value = slider.getValue();
185 options.ACCESS_JAVADOC_REQUIRED_FOR = modifiers[value - 1];
186 for (Integer key : sliderLabels.keySet()) {
187 sliderLabels.get(key).setForeground(key.intValue() <= value ? Color.black : new Color(100, 100, 100));
192 Color fore = Color.black;
193 for (int i = 0; i < modifiers.length; i++) {
194 sliderLabels.get(i + 1).setForeground(fore);
196 if (modifiers[i].equals(options.ACCESS_JAVADOC_REQUIRED_FOR)) {
197 slider.setValue(i + 1);
198 fore = new Color(100, 100, 100);
202 panel.add(slider, BorderLayout.WEST);
204 return panel;
207 public OptionsPanel() {
208 super(new GridBagLayout());
209 GridBagConstraints gc = new GridBagConstraints(0, GridBagConstraints.RELATIVE, 2, 1, 1, 1, GridBagConstraints.NORTH, GridBagConstraints.BOTH, new Insets(0,0,0,0),0,0 );
210 gc.weighty = 0;
211 add(createAdditionalJavadocTagsPanel(), gc);
212 JTabbedPane tabs = new JTabbedPane(SwingConstants.BOTTOM);
213 @NonNls String[] tags = new String[]{"@author", "@version", "@since", "@param"};
214 tabs.add(InspectionsBundle.message("inspection.javadoc.option.tab.title"), createOptionsPanel(new String[]{NONE, PUBLIC, PACKAGE_LOCAL},
215 tags,
216 TOP_LEVEL_CLASS_OPTIONS));
217 tags = new String[]{"@return", "@param", InspectionsBundle.message("inspection.javadoc.throws.or.exception.option")};
218 tabs.add(InspectionsBundle.message("inspection.javadoc.option.tab.title.method"), createOptionsPanel(new String[]{NONE, PUBLIC, PROTECTED, PACKAGE_LOCAL, PRIVATE},
219 tags,
220 METHOD_OPTIONS));
221 tabs.add(InspectionsBundle.message("inspection.javadoc.option.tab.title.field"), createOptionsPanel(new String[]{NONE, PUBLIC, PROTECTED, PACKAGE_LOCAL, PRIVATE},
222 null,
223 FIELD_OPTIONS));
224 tabs.add(InspectionsBundle.message("inspection.javadoc.option.tab.title.inner.class"), createOptionsPanel(new String[]{NONE, PUBLIC, PROTECTED, PACKAGE_LOCAL, PRIVATE},
225 null,
226 INNER_CLASS_OPTIONS));
227 add(tabs, gc);
229 final JCheckBox checkBox = new JCheckBox(InspectionsBundle.message("inspection.javadoc.option.ignore.deprecated"),
230 IGNORE_DEPRECATED);
231 checkBox.addActionListener(new ActionListener() {
232 public void actionPerformed(ActionEvent e) {
233 IGNORE_DEPRECATED = checkBox.isSelected();
236 gc.gridwidth = 1;
237 add(checkBox, gc);
238 final JCheckBox periodCheckBox = new JCheckBox(InspectionsBundle.message("inspection.javadoc.option.ignore.period"),
239 IGNORE_JAVADOC_PERIOD);
240 periodCheckBox.addActionListener(new ActionListener() {
241 public void actionPerformed(ActionEvent e) {
242 IGNORE_JAVADOC_PERIOD = periodCheckBox.isSelected();
245 add(periodCheckBox, gc);
247 final JCheckBox ignoreDuplicateThrowsCheckBox = new JCheckBox("Ignore duplicate throws tag",
248 IGNORE_DUPLICATED_THROWS);
249 ignoreDuplicateThrowsCheckBox.addActionListener(new ActionListener() {
250 public void actionPerformed(ActionEvent e) {
251 IGNORE_DUPLICATED_THROWS = ignoreDuplicateThrowsCheckBox.isSelected();
254 add(ignoreDuplicateThrowsCheckBox, gc);
257 public FieldPanel createAdditionalJavadocTagsPanel(){
258 FieldPanel additionalTagsPanel = new FieldPanel(InspectionsBundle.message("inspection.javadoc.label.text"), InspectionsBundle.message("inspection.javadoc.dialog.title"), null, null);
259 additionalTagsPanel.setPreferredSize(new Dimension(150, additionalTagsPanel.getPreferredSize().height));
260 additionalTagsPanel.getTextField().getDocument().addDocumentListener(new DocumentAdapter() {
261 protected void textChanged(DocumentEvent e) {
262 final Document document = e.getDocument();
263 try {
264 final String text = document.getText(0, document.getLength());
265 if (text != null) {
266 myAdditionalJavadocTags = text.trim();
269 catch (BadLocationException e1) {
270 LOG.error(e1);
274 additionalTagsPanel.setText(myAdditionalJavadocTags);
275 return additionalTagsPanel;
279 public JComponent createOptionsPanel() {
280 return new OptionsPanel();
283 private static ProblemDescriptor createDescriptor(@NotNull PsiElement element, String template, InspectionManager manager,
284 boolean onTheFly) {
285 return manager.createProblemDescriptor(element, template, onTheFly, (LocalQuickFix [])null, ProblemHighlightType.GENERIC_ERROR_OR_WARNING);
288 private static ProblemDescriptor createDescriptor(@NotNull PsiElement element, String template, @NotNull LocalQuickFix fix,
289 InspectionManager manager, boolean onTheFly) {
290 return manager.createProblemDescriptor(element, template, fix, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, onTheFly);
293 private static class AddMissingTagFix implements LocalQuickFix {
294 private final String myTag;
295 private final String myValue;
297 public AddMissingTagFix(@NonNls String tag, String value) {
298 myTag = tag;
299 myValue = value;
301 public AddMissingTagFix(String tag) {
302 this(tag, "");
305 @NotNull
306 public String getName() {
307 return InspectionsBundle.message("inspection.javadoc.problem.add.tag", myTag, myValue);
310 public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
311 final PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory();
312 try {
313 final PsiDocCommentOwner owner = PsiTreeUtil.getParentOfType(descriptor.getEndElement(), PsiDocCommentOwner.class);
314 if (owner != null) {
315 if (!CodeInsightUtil.preparePsiElementsForWrite(owner)) return;
316 final PsiDocComment docComment = owner.getDocComment();
317 final PsiDocTag tag = factory.createDocTagFromText("@" + myTag+" "+myValue, docComment);
318 if (docComment != null) {
319 PsiElement addedTag;
320 final PsiElement anchor = getAnchor();
321 if (anchor != null) {
322 addedTag = docComment.addBefore(tag, anchor);
324 else {
325 addedTag = docComment.add(tag);
327 moveCaretTo(addedTag);
331 catch (IncorrectOperationException e) {
332 LOG.error(e);
336 @Nullable
337 protected PsiElement getAnchor() {
338 return null;
341 private static void moveCaretTo(final PsiElement newCaretPosition) {
342 Project project = newCaretPosition.getProject();
343 final PsiFile psiFile = newCaretPosition.getContainingFile();
344 final Editor editor = FileEditorManager.getInstance(project).getSelectedTextEditor();
345 if (editor != null && IJSwingUtilities.hasFocus(editor.getComponent())) {
346 final PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
347 if (file == psiFile) {
348 editor.getCaretModel().moveToOffset(newCaretPosition.getTextRange().getEndOffset());
349 editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
354 @NotNull
355 public String getFamilyName() {
356 return InspectionsBundle.message("inspection.javadoc.problem.add.tag.family");
359 @Nullable
360 public ProblemDescriptor[] checkClass(@NotNull PsiClass psiClass, @NotNull InspectionManager manager, boolean isOnTheFly) {
361 if (psiClass instanceof PsiAnonymousClass) return null;
362 if (psiClass instanceof JspClass) return null;
363 if (psiClass instanceof PsiTypeParameter) return null;
364 if (IGNORE_DEPRECATED && psiClass.isDeprecated()) {
365 return null;
367 PsiDocComment docComment = psiClass.getDocComment();
368 final PsiIdentifier nameIdentifier = psiClass.getNameIdentifier();
369 final PsiElement elementToHighlight = nameIdentifier != null ? nameIdentifier : psiClass;
370 if (docComment == null) {
371 return isJavaDocRequired(psiClass)
372 ? new ProblemDescriptor[]{createDescriptor(elementToHighlight, REQUIRED_JAVADOC_IS_ABSENT, manager, isOnTheFly)}
373 : null;
376 PsiDocTag[] tags = docComment.getTags();
377 @NonNls String[] tagsToCheck = {"author", "version", "since"};
378 @NonNls String[] absentDescriptionKeys = {
379 "inspection.javadoc.problem.missing.author.description",
380 "inspection.javadoc.problem.missing.version.description",
381 "inspection.javadoc.problem.missing.since.description"};
383 boolean[] isTagRequired = new boolean[tagsToCheck.length];
384 boolean[] isTagPresent = new boolean[tagsToCheck.length];
386 boolean someTagsAreRequired = false;
387 for (int i = 0; i < tagsToCheck.length; i++) {
388 final String tag = tagsToCheck[i];
389 someTagsAreRequired |= isTagRequired[i] = isTagRequired(psiClass, tag);
392 if (someTagsAreRequired) {
393 for (PsiDocTag tag : tags) {
394 String tagName = tag.getName();
395 for (int i = 0; i < tagsToCheck.length; i++) {
396 final String tagToCheck = tagsToCheck[i];
397 if (tagToCheck.equals(tagName)) {
398 isTagPresent[i] = true;
404 final ArrayList<ProblemDescriptor> problems = new ArrayList<ProblemDescriptor>(2);
406 for (int i = 0; i < tagsToCheck.length; i++) {
407 final String tagToCheck = tagsToCheck[i];
408 if (isTagRequired[i] && !isTagPresent[i]) {
409 problems.add(createMissingTagDescriptor(elementToHighlight, tagToCheck, manager, isOnTheFly));
412 ArrayList<ProblemDescriptor> tagProblems = getTagValuesProblems(psiClass, tags, manager, isOnTheFly);
413 if (tagProblems != null) {
414 problems.addAll(tagProblems);
416 checkForPeriodInDoc(docComment, problems, manager, isOnTheFly);
417 checkInlineTags(manager, problems, docComment.getDescriptionElements(),
418 JavaPsiFacade.getInstance(docComment.getProject()).getJavadocManager(), isOnTheFly);
419 checkForBadCharacters(docComment, problems, manager, isOnTheFly);
420 for (PsiDocTag tag : tags) {
421 for (int i = 0; i < tagsToCheck.length; i++) {
422 final String tagToCheck = tagsToCheck[i];
423 if (tagToCheck.equals(tag.getName()) && extractTagDescription(tag).length() == 0) {
424 problems.add(createDescriptor(elementToHighlight, InspectionsBundle.message(absentDescriptionKeys[i]), manager, isOnTheFly));
429 checkDuplicateTags(tags, problems, manager, isOnTheFly);
431 if (isTagRequired(psiClass, "param") && psiClass.hasTypeParameters() && nameIdentifier != null) {
432 ArrayList<PsiTypeParameter> absentParameters = null;
433 final PsiTypeParameter[] typeParameters = psiClass.getTypeParameters();
434 for (PsiTypeParameter typeParameter : typeParameters) {
435 if (!isFound(tags, typeParameter)) {
436 if (absentParameters == null) absentParameters = new ArrayList<PsiTypeParameter>(1);
437 absentParameters.add(typeParameter);
440 if (absentParameters != null) {
441 for (PsiTypeParameter psiTypeParameter : absentParameters) {
442 problems.add(createMissingParamTagDescriptor(nameIdentifier, psiTypeParameter, manager, isOnTheFly));
447 return problems.isEmpty()
448 ? null
449 : problems.toArray(new ProblemDescriptor[problems.size()]);
452 private static ProblemDescriptor createMissingParamTagDescriptor(final PsiIdentifier nameIdentifier,
453 final PsiTypeParameter psiTypeParameter,
454 final InspectionManager manager, boolean isOnTheFly) {
455 String message = InspectionsBundle.message("inspection.javadoc.problem.missing.tag", "<code>@param</code>");
456 return createDescriptor(nameIdentifier, message, new AddMissingTagFix("param", "<" + psiTypeParameter.getName() + ">"), manager,
457 isOnTheFly);
460 @Nullable
461 public ProblemDescriptor[] checkField(@NotNull PsiField psiField, @NotNull InspectionManager manager, boolean isOnTheFly) {
462 if (IGNORE_DEPRECATED && (psiField.isDeprecated() || psiField.getContainingClass().isDeprecated())) {
463 return null;
466 PsiDocComment docComment = psiField.getDocComment();
467 if (docComment == null) {
468 return isJavaDocRequired(psiField)
469 ? new ProblemDescriptor[]{createDescriptor(psiField.getNameIdentifier(), REQUIRED_JAVADOC_IS_ABSENT, manager, isOnTheFly)}
470 : null;
473 final ArrayList<ProblemDescriptor> problems = new ArrayList<ProblemDescriptor>(2);
474 ArrayList<ProblemDescriptor> tagProblems = getTagValuesProblems(psiField, docComment.getTags(), manager, isOnTheFly);
475 if (tagProblems != null) {
476 problems.addAll(tagProblems);
478 checkInlineTags(manager, problems, docComment.getDescriptionElements(),
479 JavaPsiFacade.getInstance(docComment.getProject()).getJavadocManager(), isOnTheFly);
480 checkForPeriodInDoc(docComment, problems, manager, isOnTheFly);
481 checkDuplicateTags(docComment.getTags(), problems, manager, isOnTheFly);
482 checkForBadCharacters(docComment, problems, manager, isOnTheFly);
483 return problems.isEmpty()
484 ? null
485 : problems.toArray(new ProblemDescriptor[problems.size()]);
488 @Nullable
489 public ProblemDescriptor[] checkMethod(@NotNull PsiMethod psiMethod, @NotNull InspectionManager manager, boolean isOnTheFly) {
490 if (psiMethod instanceof JspHolderMethod) return null;
491 if (IGNORE_DEPRECATED && (psiMethod.isDeprecated() || psiMethod.getContainingClass().isDeprecated())) {
492 return null;
494 PsiDocComment docComment = psiMethod.getDocComment();
495 final PsiMethod[] superMethods = psiMethod.findSuperMethods();
496 if (docComment == null) {
497 if (isJavaDocRequired(psiMethod)) {
498 if (superMethods.length > 0) return null;
499 ExtensionPoint<Condition<PsiMember>> point = Extensions.getRootArea().getExtensionPoint(ExtensionPoints.JAVADOC_LOCAL);
500 final Condition<PsiMember>[] addins = point.getExtensions();
501 for (Condition<PsiMember> addin : addins) {
502 if (addin.value(psiMethod)) return null;
504 if (superMethods.length == 0) {
505 final PsiIdentifier nameIdentifier = psiMethod.getNameIdentifier();
506 return nameIdentifier != null ? new ProblemDescriptor[] { createDescriptor(nameIdentifier, REQUIRED_JAVADOC_IS_ABSENT, manager,
507 isOnTheFly)} : null;
509 else {
510 return null;
513 else {
514 return null;
518 final PsiElement[] descriptionElements = docComment.getDescriptionElements();
519 for (PsiElement descriptionElement : descriptionElements) {
520 if (descriptionElement instanceof PsiInlineDocTag) {
521 if ("inheritDoc".equals(((PsiInlineDocTag)descriptionElement).getName())) return null;
525 final ArrayList<ProblemDescriptor> problems = new ArrayList<ProblemDescriptor>(2);
527 checkInlineTags(manager, problems, descriptionElements,
528 JavaPsiFacade.getInstance(docComment.getProject()).getJavadocManager(), isOnTheFly);
530 final PsiDocTag tagByName = docComment.findTagByName("inheritDoc");
531 if (tagByName != null) {
532 final String tagName = tagByName.getName();
533 final JavadocTagInfo tagInfo = JavaPsiFacade.getInstance(tagByName.getProject()).getJavadocManager().getTagInfo(tagName);
534 if (tagInfo != null && tagInfo.isValidInContext(psiMethod)){
535 return null;
539 PsiDocTag[] tags = docComment.getTags();
541 boolean isReturnRequired = false;
542 boolean isReturnAbsent = true;
543 if (superMethods.length == 0 && !psiMethod.isConstructor() && PsiType.VOID != psiMethod.getReturnType() && isTagRequired(psiMethod, "return")) {
544 isReturnRequired = true;
545 for (PsiDocTag tag : tags) {
546 if ("return".equals(tag.getName())) {
547 isReturnAbsent = false;
548 break;
553 ArrayList<PsiParameter> absentParameters = null;
554 if (superMethods.length == 0 && isTagRequired(psiMethod, "param") ) {
555 PsiParameter[] params = psiMethod.getParameterList().getParameters();
556 for (PsiParameter param : params) {
557 if (!isFound(tags, param)) {
558 if (absentParameters == null) absentParameters = new ArrayList<PsiParameter>(2);
559 absentParameters.add(param);
566 if (isReturnRequired && isReturnAbsent) {
567 final PsiIdentifier psiIdentifier = psiMethod.getNameIdentifier();
568 if (psiIdentifier != null) {
569 problems.add(createMissingTagDescriptor(psiIdentifier, "return", manager, isOnTheFly));
573 if (absentParameters != null) {
574 for (PsiParameter psiParameter : absentParameters) {
575 final PsiIdentifier nameIdentifier = psiMethod.getNameIdentifier();
576 if (nameIdentifier != null) {
577 problems.add(createMissingParamTagDescriptor(nameIdentifier, psiParameter, manager, isOnTheFly));
582 for (PsiDocTag tag : tags) {
583 if ("param".equals(tag.getName())) {
584 final PsiElement[] dataElements = tag.getDataElements();
585 final PsiDocTagValue valueElement = tag.getValueElement();
586 boolean hasProblemsWithTag = dataElements.length < 2;
587 if (!hasProblemsWithTag) {
588 final StringBuilder buf = new StringBuilder();
589 for (PsiElement element : dataElements) {
590 if (element != valueElement){
591 buf.append(element.getText());
594 hasProblemsWithTag = buf.toString().trim().length() == 0;
596 if (hasProblemsWithTag) {
597 if (valueElement != null) {
598 problems.add(createDescriptor(valueElement,
599 InspectionsBundle.message("inspection.javadoc.method.problem.missing.tag.description", "<code>@param " + valueElement.getText() + "</code>"),
600 manager, isOnTheFly));
607 if (superMethods.length == 0 && isTagRequired(psiMethod, "@throws") && psiMethod.getThrowsList().getReferencedTypes().length > 0) {
608 final Map<PsiClassType, PsiClass> declaredExceptions = new HashMap<PsiClassType, PsiClass>();
609 final PsiClassType[] classTypes = psiMethod.getThrowsList().getReferencedTypes();
610 for (PsiClassType classType : classTypes) {
611 final PsiClass psiClass = classType.resolve();
612 if (psiClass != null){
613 declaredExceptions.put(classType, psiClass);
616 processThrowsTags(tags, declaredExceptions, manager, problems, isOnTheFly);
617 if (!declaredExceptions.isEmpty()) {
618 for (PsiClassType declaredException : declaredExceptions.keySet()) {
619 problems.add(createMissingThrowsTagDescriptor(psiMethod, manager, declaredException, isOnTheFly));
624 ArrayList<ProblemDescriptor> tagProblems = getTagValuesProblems(psiMethod, tags, manager, isOnTheFly);
625 if (tagProblems != null) {
626 problems.addAll(tagProblems);
629 checkForPeriodInDoc(docComment, problems, manager, isOnTheFly);
630 checkForBadCharacters(docComment, problems, manager, isOnTheFly);
631 for (PsiDocTag tag : tags) {
632 if ("param".equals(tag.getName())) {
633 if (extractTagDescription(tag).length() == 0) {
634 PsiDocTagValue value = tag.getValueElement();
635 if (value instanceof PsiDocParamRef) {
636 PsiDocParamRef paramRef = (PsiDocParamRef)value;
637 PsiParameter[] params = psiMethod.getParameterList().getParameters();
638 for (PsiParameter param : params) {
639 if (paramRef.getReference().isReferenceTo(param)) {
640 problems.add(createDescriptor(value,
641 InspectionsBundle.message("inspection.javadoc.method.problem.descriptor", "<code>@param</code>", "<code>" + param.getName() + "</code>"),
642 manager, isOnTheFly));
648 else
649 if ("return".equals(tag.getName())) {
650 if (extractTagDescription(tag).length() == 0) {
651 String message = InspectionsBundle.message("inspection.javadoc.method.problem.missing.tag.description", "<code>@return</code>");
652 ProblemDescriptor descriptor = manager.createProblemDescriptor(tag.getNameElement(), message, null, ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
653 isOnTheFly, true);
654 problems.add(descriptor);
659 checkDuplicateTags(tags, problems, manager, isOnTheFly);
661 return problems.isEmpty()
662 ? null
663 : problems.toArray(new ProblemDescriptor[problems.size()]);
666 private static boolean isFound(final PsiDocTag[] tags, final PsiElement param) {
667 for (PsiDocTag tag : tags) {
668 if ("param".equals(tag.getName())) {
669 PsiDocTagValue value = tag.getValueElement();
670 if (value instanceof PsiDocParamRef) {
671 PsiDocParamRef paramRef = (PsiDocParamRef)value;
672 final PsiReference psiReference = paramRef.getReference();
673 if (psiReference != null && psiReference.isReferenceTo(param)) {
674 return true;
679 return false;
682 private static void processThrowsTags(final PsiDocTag[] tags,
683 final Map<PsiClassType, PsiClass> declaredExceptions,
684 final InspectionManager mananger,
685 @NotNull final ArrayList<ProblemDescriptor> problems, boolean isOnTheFly) {
686 for (PsiDocTag tag : tags) {
687 if ("throws".equals(tag.getName()) || "exception".equals(tag.getName())) {
688 final PsiDocTagValue value = tag.getValueElement();
689 if (value == null) continue;
690 final PsiElement firstChild = value.getFirstChild();
691 if (firstChild == null) continue;
692 final PsiElement psiElement = firstChild.getFirstChild();
693 if (!(psiElement instanceof PsiJavaCodeReferenceElement)) continue;
694 final PsiJavaCodeReferenceElement ref = (PsiJavaCodeReferenceElement)psiElement;
695 final PsiElement element = ref.resolve();
696 if (element instanceof PsiClass){
697 final PsiClass exceptionClass = (PsiClass)element;
698 for (Iterator<PsiClassType> it = declaredExceptions.keySet().iterator(); it.hasNext();) {
699 PsiClassType classType = it.next();
700 final PsiClass psiClass = declaredExceptions.get(classType);
701 if (InheritanceUtil.isInheritorOrSelf(exceptionClass, psiClass, true)) {
702 if (extractThrowsTagDescription(tag).length() == 0) {
703 problems.add(createDescriptor(tag.getNameElement(), InspectionsBundle.message("inspection.javadoc.method.problem.missing.tag.description", "<code>" + tag.getName() + "</code>"), mananger,
704 isOnTheFly));
706 it.remove();
714 @Nullable
715 private static ProblemDescriptor createMissingThrowsTagDescriptor(final PsiMethod method,
716 final InspectionManager manager,
717 final PsiClassType exceptionClassType, boolean isOnTheFly) {
718 @NonNls String tag = "throws";
719 String message = InspectionsBundle.message("inspection.javadoc.problem.missing.tag", "<code>@" + tag + "</code> " + exceptionClassType.getCanonicalText());
720 final String firstDeclaredException = exceptionClassType.getCanonicalText();
721 final PsiIdentifier nameIdentifier = method.getNameIdentifier();
722 return nameIdentifier != null ? createDescriptor(nameIdentifier, message,new AddMissingTagFix(tag, firstDeclaredException), manager,
723 isOnTheFly) : null;
726 private static ProblemDescriptor createMissingTagDescriptor(PsiElement elementToHighlight,
727 @NonNls String tag,
728 final InspectionManager manager, boolean isOnTheFly) {
729 String message = InspectionsBundle.message("inspection.javadoc.problem.missing.tag", "<code>@" + tag + "</code>");
730 return createDescriptor(elementToHighlight, message,new AddMissingTagFix(tag), manager, isOnTheFly);
732 private static ProblemDescriptor createMissingParamTagDescriptor(PsiElement elementToHighlight,
733 PsiParameter param,
734 final InspectionManager manager, boolean isOnTheFly) {
735 String message = InspectionsBundle.message("inspection.javadoc.method.problem.missing.param.tag", "<code>@param</code>", "<code>" + param.getName() + "</code>");
736 return createDescriptor(elementToHighlight, message, new AddMissingParamTagFix(param), manager, isOnTheFly);
739 private static class AddMissingParamTagFix extends AddMissingTagFix {
740 private final PsiParameter myParam;
742 public AddMissingParamTagFix(final PsiParameter param) {
743 super("param", param.getName());
744 myParam = param;
747 @NotNull
748 public String getName() {
749 return InspectionsBundle.message("inspection.javadoc.problem.add.param.tag", myParam.getName());
752 @Nullable
753 protected PsiElement getAnchor() {
754 final PsiMethod psiMethod = PsiTreeUtil.getParentOfType(myParam, PsiMethod.class);
755 LOG.assertTrue(psiMethod != null);
756 final PsiDocComment docComment = psiMethod.getDocComment();
757 LOG.assertTrue(docComment != null);
758 PsiDocTag[] tags = docComment.findTagsByName("param");
759 if (tags.length == 0) { //insert as first tag or append to description
760 tags = docComment.getTags();
761 if (tags.length == 0) return null;
762 return tags[0];
765 PsiParameter nextParam = PsiTreeUtil.getNextSiblingOfType(myParam, PsiParameter.class);
766 while (nextParam != null) {
767 for (PsiDocTag tag : tags) {
768 if (matches(nextParam, tag)) {
769 return tag;
772 nextParam = PsiTreeUtil.getNextSiblingOfType(nextParam, PsiParameter.class);
775 PsiParameter prevParam = PsiTreeUtil.getPrevSiblingOfType(myParam, PsiParameter.class);
776 while (prevParam != null) {
777 for (PsiDocTag tag : tags) {
778 if (matches(prevParam, tag)) {
779 return PsiTreeUtil.getNextSiblingOfType(tag, PsiDocTag.class);
782 prevParam = PsiTreeUtil.getPrevSiblingOfType(prevParam, PsiParameter.class);
785 return null;
788 private static boolean matches(final PsiParameter param, final PsiDocTag tag) {
789 return tag.getValueElement().getText().trim().startsWith(param.getName());
793 private static String extractTagDescription(PsiDocTag tag) {
794 StringBuilder buf = new StringBuilder();
795 PsiElement[] children = tag.getChildren();
796 for (PsiElement child : children) {
797 if (child instanceof PsiDocToken) {
798 PsiDocToken token = (PsiDocToken)child;
799 if (token.getTokenType() == JavaDocTokenType.DOC_COMMENT_DATA) {
800 buf.append(token.getText());
803 else if (child instanceof PsiDocTagValue) {
804 buf.append(child.getText());
805 } else if (child instanceof PsiInlineDocTag) {
806 buf.append(child.getText());
810 String s = buf.toString();
811 return s.trim();
814 private static String extractThrowsTagDescription(PsiDocTag tag) {
815 StringBuilder buf = new StringBuilder();
816 PsiElement[] children = tag.getChildren();
817 for (PsiElement child : children) {
818 if (child instanceof PsiDocToken) {
819 PsiDocToken token = (PsiDocToken)child;
820 if (token.getTokenType() == JavaDocTokenType.DOC_COMMENT_DATA) {
821 buf.append(token.getText());
826 return buf.toString().trim();
829 private void checkForBadCharacters(PsiDocComment docComment,
830 final ArrayList<ProblemDescriptor> problems,
831 final InspectionManager manager, final boolean onTheFly) {
832 docComment.accept(new PsiRecursiveElementVisitor(){
833 @Override
834 public void visitElement(PsiElement element) {
835 super.visitElement(element);
836 final ASTNode node = element.getNode();
837 if (node != null) {
838 if (node.getElementType() == JavaDocTokenType.DOC_COMMENT_BAD_CHARACTER) {
839 problems.add(manager.createProblemDescriptor(element, "Illegal character", (LocalQuickFix)null, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, onTheFly));
846 private void checkForPeriodInDoc(PsiDocComment docComment,
847 ArrayList<ProblemDescriptor> problems,
848 InspectionManager manager, boolean onTheFly) {
849 if (IGNORE_JAVADOC_PERIOD) return;
850 PsiDocTag[] tags = docComment.getTags();
851 int dotIndex = docComment.getText().indexOf('.');
852 int tagOffset = 0;
853 if (dotIndex >= 0) { //need to find first valid tag
854 final PsiDocCommentOwner owner = PsiTreeUtil.getParentOfType(docComment, PsiDocCommentOwner.class);
855 for (PsiDocTag tag : tags) {
856 final String tagName = tag.getName();
857 final JavadocTagInfo tagInfo = JavaPsiFacade.getInstance(tag.getProject()).getJavadocManager().getTagInfo(tagName);
858 if (tagInfo != null && tagInfo.isValidInContext(owner) && !tagInfo.isInline()) {
859 tagOffset = tag.getTextOffset();
860 break;
865 if (dotIndex == -1 || tagOffset > 0 && dotIndex + docComment.getTextOffset() > tagOffset) {
866 problems.add(manager.createProblemDescriptor(docComment.getFirstChild(),
867 InspectionsBundle.message("inspection.javadoc.problem.descriptor1"),
868 null,
869 ProblemHighlightType.GENERIC_ERROR_OR_WARNING, onTheFly, false));
873 @Nullable
874 private ArrayList<ProblemDescriptor> getTagValuesProblems(PsiDocCommentOwner context, PsiDocTag[] tags, InspectionManager inspectionManager,
875 boolean isOnTheFly) {
876 final ArrayList<ProblemDescriptor> problems = new ArrayList<ProblemDescriptor>(2);
877 nextTag:
878 for (PsiDocTag tag : tags) {
879 final JavadocManager manager = JavaPsiFacade.getInstance(tag.getProject()).getJavadocManager();
880 String tagName = tag.getName();
881 JavadocTagInfo tagInfo = manager.getTagInfo(tagName);
883 if (tagInfo == null || !tagInfo.isValidInContext(context)) {
884 final StringTokenizer tokenizer = new StringTokenizer(myAdditionalJavadocTags, ", ");
885 while (tokenizer.hasMoreTokens()) {
886 if (Comparing.strEqual(tagName, tokenizer.nextToken())) continue nextTag;
889 if (tagInfo == null){
890 problems.add(createDescriptor(tag.getNameElement(), InspectionsBundle.message("inspection.javadoc.problem.wrong.tag", "<code>" + tagName + "</code>"), new AddUnknownTagToCustoms(tag), inspectionManager,
891 isOnTheFly));
892 } else {
893 problems.add(createDescriptor(tag.getNameElement(), InspectionsBundle.message("inspection.javadoc.problem.disallowed.tag", "<code>" + tagName + "</code>"), new AddUnknownTagToCustoms(tag), inspectionManager,
894 isOnTheFly));
899 PsiDocTagValue value = tag.getValueElement();
900 final JavadocTagInfo info = manager.getTagInfo(tagName);
901 if (info != null && !info.isValidInContext(context)) continue;
902 String message = info == null ? null : info.checkTagValue(value);
904 final PsiReference reference = value != null ? value.getReference() : null;
905 if (message == null && reference != null) {
906 PsiElement element = reference.resolve();
907 if (element == null) {
908 final int textOffset = value.getTextOffset();
910 if (textOffset == value.getTextRange().getEndOffset()) {
911 problems.add(inspectionManager.createProblemDescriptor(tag, InspectionsBundle.message("inspection.javadoc.problem.name.expected"), null, ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
912 isOnTheFly, true));
917 if (message != null) {
918 final PsiDocTagValue valueElement = tag.getValueElement();
919 if (valueElement == null){
920 problems.add(inspectionManager.createProblemDescriptor(tag, InspectionsBundle.message("inspection.javadoc.method.problem.missing.tag.description", "<code>" + tag.getName() + "</code>"), null, ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
921 isOnTheFly, true));
922 } else {
923 problems.add(createDescriptor(valueElement, message, inspectionManager, isOnTheFly));
926 checkInlineTags(inspectionManager, problems, tag.getDataElements(), manager, isOnTheFly);
929 return problems.isEmpty() ? null : problems;
932 private void checkInlineTags(final InspectionManager inspectionManager,
933 final ArrayList<ProblemDescriptor> problems,
934 final PsiElement[] dataElements,
935 final JavadocManager manager, boolean isOnTheFly) {
936 for (PsiElement dataElement : dataElements) {
937 if (dataElement instanceof PsiInlineDocTag) {
938 final PsiInlineDocTag inlineDocTag = (PsiInlineDocTag)dataElement;
939 final PsiElement nameElement = inlineDocTag.getNameElement();
940 if (manager.getTagInfo(inlineDocTag.getName()) == null) {
941 if (nameElement != null) {
942 problems.add(createDescriptor(nameElement, InspectionsBundle.message("inspection.javadoc.problem.wrong.tag", "<code>" + inlineDocTag.getName() + "</code>"), new AddUnknownTagToCustoms(inlineDocTag), inspectionManager,
943 isOnTheFly));
946 final PsiDocTagValue value = inlineDocTag.getValueElement();
947 if (value != null) {
948 final PsiReference reference = value.getReference();
949 if (reference != null) {
950 final PsiElement ref = reference.resolve();
951 if (ref != null){
952 if (PsiTreeUtil.getParentOfType(inlineDocTag, PsiDocCommentOwner.class) == PsiTreeUtil.getParentOfType(ref, PsiDocCommentOwner.class, false)) {
953 if (nameElement != null) {
954 problems.add(createDescriptor(nameElement, InspectionsBundle.message("inspection.javadoc.problem.pointing.to.itself"), inspectionManager,
955 isOnTheFly));
965 @SuppressWarnings({"SimplifiableIfStatement"})
966 private boolean isTagRequired(PsiElement context, @NonNls String tag) {
967 if (context instanceof PsiClass) {
968 if (PsiTreeUtil.getParentOfType(context, PsiClass.class) != null) {
969 return isTagRequired(INNER_CLASS_OPTIONS, tag);
972 return isTagRequired(TOP_LEVEL_CLASS_OPTIONS, tag);
975 if (context instanceof PsiMethod) {
976 return isTagRequired(METHOD_OPTIONS, tag);
979 if (context instanceof PsiField) {
980 return isTagRequired(FIELD_OPTIONS, tag);
983 return false;
986 private static boolean isTagRequired(Options options, String tag) {
987 return options.REQUIRED_TAGS.contains(tag);
990 private boolean isJavaDocRequired(PsiModifierListOwner psiElement) {
991 final RefJavaUtil refUtil = RefJavaUtil.getInstance();
992 int actualAccess = getAccessNumber(refUtil.getAccessModifier(psiElement));
993 if (psiElement instanceof PsiClass) {
994 PsiClass psiClass = (PsiClass)psiElement;
995 if (PsiTreeUtil.getParentOfType(psiClass, PsiClass.class) != null) {
996 return actualAccess <= getAccessNumber(INNER_CLASS_OPTIONS.ACCESS_JAVADOC_REQUIRED_FOR);
999 return actualAccess <= getAccessNumber(TOP_LEVEL_CLASS_OPTIONS.ACCESS_JAVADOC_REQUIRED_FOR);
1002 if (psiElement instanceof PsiMethod) {
1003 psiElement = PsiTreeUtil.getParentOfType(psiElement, PsiClass.class);
1004 while (psiElement != null) {
1005 actualAccess = Math.max(actualAccess, getAccessNumber(refUtil.getAccessModifier(psiElement)));
1006 psiElement = PsiTreeUtil.getParentOfType(psiElement, PsiClass.class);
1009 return actualAccess <= getAccessNumber(METHOD_OPTIONS.ACCESS_JAVADOC_REQUIRED_FOR);
1012 if (psiElement instanceof PsiField) {
1013 psiElement = PsiTreeUtil.getParentOfType(psiElement, PsiClass.class);
1014 while (psiElement != null) {
1015 actualAccess = Math.max(actualAccess, getAccessNumber(refUtil.getAccessModifier(psiElement)));
1016 psiElement = PsiTreeUtil.getParentOfType(psiElement, PsiClass.class);
1019 return actualAccess <= getAccessNumber(FIELD_OPTIONS.ACCESS_JAVADOC_REQUIRED_FOR);
1022 return false;
1025 private void checkDuplicateTags(final PsiDocTag[] tags,
1026 ArrayList<ProblemDescriptor> problems,
1027 final InspectionManager manager, boolean isOnTheFly) {
1028 Set<String> documentedParamNames = null;
1029 Set<String> documentedExceptions = null;
1030 Set<String> uniqueTags = null;
1031 for(PsiDocTag tag: tags) {
1032 if ("param".equals(tag.getName())) {
1033 PsiDocTagValue value = tag.getValueElement();
1034 if (value instanceof PsiDocParamRef) {
1035 PsiDocParamRef paramRef = (PsiDocParamRef)value;
1036 final PsiReference reference = paramRef.getReference();
1037 if (reference != null) {
1038 final String paramName = reference.getCanonicalText();
1039 if (documentedParamNames == null) {
1040 documentedParamNames = new HashSet<String>();
1042 if (documentedParamNames.contains(paramName)) {
1043 problems.add(createDescriptor(tag.getNameElement(), InspectionsBundle.message("inspection.javadoc.problem.duplicate.param", paramName), manager,
1044 isOnTheFly));
1046 documentedParamNames.add(paramName);
1050 else if (!IGNORE_DUPLICATED_THROWS && ("throws".equals(tag.getName()) || "exception".equals(tag.getName()))) {
1051 PsiDocTagValue value = tag.getValueElement();
1052 if (value != null) {
1053 final PsiElement firstChild = value.getFirstChild();
1054 if (firstChild != null && firstChild.getFirstChild() instanceof PsiJavaCodeReferenceElement) {
1055 PsiJavaCodeReferenceElement refElement = (PsiJavaCodeReferenceElement) firstChild.getFirstChild();
1056 if (refElement != null) {
1057 PsiElement element = refElement.resolve();
1058 if (element instanceof PsiClass) {
1059 String fqName = ((PsiClass)element).getQualifiedName();
1060 if (documentedExceptions == null) {
1061 documentedExceptions = new HashSet<String>();
1063 if (documentedExceptions.contains(fqName)) {
1064 problems.add(createDescriptor(tag.getNameElement(),
1065 InspectionsBundle.message("inspection.javadoc.problem.duplicate.throws", fqName),
1066 manager, isOnTheFly));
1068 documentedExceptions.add(fqName);
1074 else if (JavaDocLocalInspection.ourUniqueTags.contains(tag.getName())) {
1075 if (uniqueTags == null) {
1076 uniqueTags = new HashSet<String>();
1078 if (uniqueTags.contains(tag.getName())) {
1079 problems.add(createDescriptor(tag.getNameElement(), InspectionsBundle.message("inspection.javadoc.problem.duplicate.tag", tag.getName()), manager,
1080 isOnTheFly));
1082 uniqueTags.add(tag.getName());
1087 private static int getAccessNumber(@NonNls String accessModifier) {
1088 if (accessModifier.startsWith("none")) return 0;
1089 if (accessModifier.startsWith("public")) return 1;
1090 if (accessModifier.startsWith("protected")) return 2;
1091 if (accessModifier.startsWith("package")) return 3;
1092 if (accessModifier.startsWith("private")) return 4;
1094 return 5;
1097 @NotNull
1098 public String getDisplayName() {
1099 return InspectionsBundle.message("inspection.javadoc.display.name");
1102 @NotNull
1103 public String getGroupDisplayName() {
1104 return "";
1107 @NotNull
1108 public String getShortName() {
1109 return SHORT_NAME;
1112 private class AddUnknownTagToCustoms implements LocalQuickFix {
1113 PsiDocTag myTag;
1115 public AddUnknownTagToCustoms(PsiDocTag tag) {
1116 myTag = tag;
1119 @NotNull
1120 public String getName() {
1121 return QuickFixBundle.message("add.doctag.to.custom.tags", myTag.getName());
1124 @NotNull
1125 public String getFamilyName() {
1126 return QuickFixBundle.message("fix.javadoc.family");
1129 public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
1130 if (myTag == null || !myTag.isValid()) return;
1131 if (myAdditionalJavadocTags.length() > 0) {
1132 myAdditionalJavadocTags += "," + myTag.getName();
1134 else {
1135 myAdditionalJavadocTags = myTag.getName();
1137 final InspectionProfile inspectionProfile =
1138 InspectionProjectProfileManager.getInstance(project).getInspectionProfile();
1139 //correct save settings
1140 ((ModifiableModel)inspectionProfile).isProperSetting(HighlightDisplayKey.find(SHORT_NAME));
1141 InspectionProfileManager.getInstance().fireProfileChanged(inspectionProfile);
1142 //TODO lesya
1146 try {
1147 inspectionProfile.save();
1149 catch (IOException e) {
1150 Messages.showErrorDialog(project, e.getMessage(), CommonBundle.getErrorTitle());