View Javadoc
1   ////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code for adherence to a set of rules.
3   // Copyright (C) 2001-2017 the original author or authors.
4   //
5   // This library is free software; you can redistribute it and/or
6   // modify it under the terms of the GNU Lesser General Public
7   // License as published by the Free Software Foundation; either
8   // version 2.1 of the License, or (at your option) any later version.
9   //
10  // This library is distributed in the hope that it will be useful,
11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  // Lesser General Public License for more details.
14  //
15  // You should have received a copy of the GNU Lesser General Public
16  // License along with this library; if not, write to the Free Software
17  // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  ////////////////////////////////////////////////////////////////////////////////
19  
20  package com.puppycrawl.tools.checkstyle.checks.annotation;
21  
22  import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
23  import com.puppycrawl.tools.checkstyle.api.DetailAST;
24  import com.puppycrawl.tools.checkstyle.api.TokenTypes;
25  import com.puppycrawl.tools.checkstyle.utils.CommonUtils;
26  
27  /**
28   * The check does verifying that annotations are located on the same line with their targets.
29   * Verifying with this check is not good practice, but it is using by some style guides.
30   * @author zenigata
31   */
32  public class AnnotationOnSameLineCheck extends AbstractCheck {
33  
34      /** A key is pointing to the warning message text in "messages.properties" file. */
35      public static final String MSG_KEY_ANNOTATION_ON_SAME_LINE = "annotation.same.line";
36  
37      @Override
38      public int[] getDefaultTokens() {
39          return new int[] {
40              TokenTypes.CLASS_DEF,
41              TokenTypes.INTERFACE_DEF,
42              TokenTypes.ENUM_DEF,
43              TokenTypes.METHOD_DEF,
44              TokenTypes.CTOR_DEF,
45              TokenTypes.VARIABLE_DEF,
46          };
47      }
48  
49      @Override
50      public int[] getAcceptableTokens() {
51          return new int[] {
52              TokenTypes.CLASS_DEF,
53              TokenTypes.INTERFACE_DEF,
54              TokenTypes.ENUM_DEF,
55              TokenTypes.METHOD_DEF,
56              TokenTypes.CTOR_DEF,
57              TokenTypes.VARIABLE_DEF,
58              TokenTypes.PARAMETER_DEF,
59              TokenTypes.ANNOTATION_DEF,
60              TokenTypes.TYPECAST,
61              TokenTypes.LITERAL_THROWS,
62              TokenTypes.IMPLEMENTS_CLAUSE,
63              TokenTypes.TYPE_ARGUMENT,
64              TokenTypes.LITERAL_NEW,
65              TokenTypes.DOT,
66              TokenTypes.ANNOTATION_FIELD_DEF,
67          };
68      }
69  
70      @Override
71      public int[] getRequiredTokens() {
72          return CommonUtils.EMPTY_INT_ARRAY;
73      }
74  
75      @Override
76      public void visitToken(DetailAST ast) {
77          DetailAST nodeWithAnnotations = ast;
78          if (ast.getType() == TokenTypes.TYPECAST) {
79              nodeWithAnnotations = ast.findFirstToken(TokenTypes.TYPE);
80          }
81          DetailAST modifiersNode = nodeWithAnnotations.findFirstToken(TokenTypes.MODIFIERS);
82          if (modifiersNode == null) {
83              modifiersNode = nodeWithAnnotations.findFirstToken(TokenTypes.ANNOTATIONS);
84          }
85          if (modifiersNode != null) {
86              for (DetailAST annotationNode = modifiersNode.getFirstChild();
87                      annotationNode != null;
88                      annotationNode = annotationNode.getNextSibling()) {
89                  if (annotationNode.getType() == TokenTypes.ANNOTATION
90                          && annotationNode.getLineNo() != getNextNode(annotationNode).getLineNo()) {
91                      log(annotationNode.getLineNo(), MSG_KEY_ANNOTATION_ON_SAME_LINE,
92                            getAnnotationName(annotationNode));
93                  }
94              }
95          }
96      }
97  
98      /**
99       * Finds next node of ast tree.
100      * @param node current node
101      * @return node that is next to given
102      */
103     private static DetailAST getNextNode(DetailAST node) {
104         DetailAST nextNode = node.getNextSibling();
105         if (nextNode == null) {
106             nextNode = node.getParent().getNextSibling();
107         }
108         return nextNode;
109     }
110 
111     /**
112      * Returns the name of the given annotation.
113      * @param annotation annotation node.
114      * @return annotation name.
115      */
116     private static String getAnnotationName(DetailAST annotation) {
117         DetailAST identNode = annotation.findFirstToken(TokenTypes.IDENT);
118         if (identNode == null) {
119             identNode = annotation.findFirstToken(TokenTypes.DOT).getLastChild();
120         }
121         return identNode.getText();
122     }
123 
124 }