Cleanup: NotNull/Nullable
[idea/community.git] / java / java-analysis-impl / src / com / intellij / codeInspection / BlockMarkerCommentsInspection.java
1 // Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
2 package com.intellij.codeInspection;
3
4 import com.intellij.lang.Commenter;
5 import com.intellij.lang.LanguageCommenters;
6 import com.intellij.openapi.project.Project;
7 import com.intellij.openapi.util.text.StringUtil;
8 import com.intellij.patterns.ElementPattern;
9 import com.intellij.patterns.PatternCondition;
10 import com.intellij.patterns.PsiJavaElementPattern;
11 import com.intellij.psi.*;
12 import com.intellij.psi.tree.IElementType;
13 import com.intellij.util.ProcessingContext;
14 import org.jetbrains.annotations.Nls;
15 import org.jetbrains.annotations.NotNull;
16
17 import static com.intellij.patterns.PsiJavaPatterns.*;
18
19 /**
20  * @author Dmitry Batkovich
21  */
22 public class BlockMarkerCommentsInspection extends AbstractBaseJavaLocalInspectionTool {
23   private static final PsiJavaElementPattern ANONYMOUS_CLASS_MARKER_PATTERN = psiElement().
24     withParent(psiElement(PsiDeclarationStatement.class, PsiExpressionStatement.class))
25     .afterSiblingSkipping(or(psiElement(PsiWhiteSpace.class), psiElement(PsiJavaToken.class).with(new PatternCondition<PsiJavaToken>(null) {
26                             @Override
27                             public boolean accepts(@NotNull final PsiJavaToken psiJavaToken, final ProcessingContext context) {
28                               return psiJavaToken.getTokenType().equals(JavaTokenType.SEMICOLON);
29                             }
30                           })),
31                           psiElement(PsiLocalVariable.class, PsiAssignmentExpression.class)
32                             .withChild(psiElement(PsiNewExpression.class).withChild(psiElement(PsiAnonymousClass.class))));
33   private static final PsiJavaElementPattern CLASS_MARKER_PATTERN = psiElement().
34     withParent(PsiClass.class).
35     afterSiblingSkipping(psiElement(PsiWhiteSpace.class), psiElement(PsiJavaToken.class).with(new PatternCondition<PsiJavaToken>(null) {
36       @Override
37       public boolean accepts(@NotNull final PsiJavaToken token, final ProcessingContext context) {
38         return JavaTokenType.RBRACE.equals(token.getTokenType());
39       }
40     }));
41   private static final PsiJavaElementPattern TRY_CATCH_MARKER_PATTERN = psiElement().
42     withParent(PsiTryStatement.class).
43     afterSiblingSkipping(psiElement(PsiWhiteSpace.class), psiElement(PsiCodeBlock.class, PsiCatchSection.class));
44   private static final PsiJavaElementPattern LOOP_OR_IF_MARKER =
45     psiElement().afterSiblingSkipping(psiElement(PsiWhiteSpace.class), psiElement(PsiCodeBlock.class)).
46       withParent(psiElement(PsiBlockStatement.class).withParent(psiElement(PsiLoopStatement.class, PsiIfStatement.class)));
47   private static final PsiJavaElementPattern METHOD_MARKER_PATTERN =
48     psiElement().withParent(PsiMethod.class).afterSiblingSkipping(psiElement(PsiWhiteSpace.class), psiElement(PsiCodeBlock.class));
49
50   private static final ElementPattern MARKER_PATTERN = or(ANONYMOUS_CLASS_MARKER_PATTERN,
51                                                           CLASS_MARKER_PATTERN,
52                                                           TRY_CATCH_MARKER_PATTERN,
53                                                           LOOP_OR_IF_MARKER,
54                                                           METHOD_MARKER_PATTERN);
55
56   private static final String END_WORD = "end";
57
58   @NotNull
59   @Override
60   public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, final boolean isOnTheFly) {
61     return new PsiElementVisitor() {
62       @Override
63       public void visitComment(final PsiComment element) {
64         final IElementType tokenType = element.getTokenType();
65         if (!(tokenType.equals(JavaTokenType.END_OF_LINE_COMMENT))) {
66           return;
67         }
68         final Commenter commenter = LanguageCommenters.INSTANCE.forLanguage(element.getLanguage());
69         String rawCommentText = element.getText();
70         final String prefix = commenter.getLineCommentPrefix();
71         if (prefix != null && rawCommentText.startsWith(prefix)) {
72           rawCommentText = rawCommentText.substring(prefix.length());
73         }
74         final String commentText = rawCommentText.trim().toLowerCase();
75         if (!commentText.startsWith(END_WORD) || StringUtil.split(commentText, " ").size() > 3) {
76           return;
77         }
78         if (MARKER_PATTERN.accepts(element)) {
79           holder.registerProblem(element, "Redundant block marker", new LocalQuickFix() {
80             @NotNull
81             @Override
82             public String getFamilyName() {
83               return "Remove block marker comments";
84             }
85
86             @Override
87             public void applyFix(@NotNull final Project project, @NotNull final ProblemDescriptor descriptor) {
88               descriptor.getPsiElement().delete();
89             }
90           });
91         }
92       }
93     };
94   }
95
96   @Nls
97   @NotNull
98   @Override
99   public String getDisplayName() {
100     return "Block marker comment";
101   }
102 }