1 ///////////////////////////////////////////////////////////////////////////////////////////////
2 // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
3 // Copyright (C) 2001-2024 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.StatelessCheck;
23 import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
24 import com.puppycrawl.tools.checkstyle.api.DetailAST;
25 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
26 import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
27 import com.puppycrawl.tools.checkstyle.utils.TokenUtil;
28
29 /**
30 * <p>
31 * Checks that annotations are located on the same line with their targets.
32 * Verifying with this check is not good practice, but it is using by some style guides.
33 * </p>
34 * <ul>
35 * <li>
36 * Property {@code tokens} - tokens to check
37 * Type is {@code java.lang.String[]}.
38 * Validation type is {@code tokenSet}.
39 * Default value is:
40 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#CLASS_DEF">
41 * CLASS_DEF</a>,
42 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#INTERFACE_DEF">
43 * INTERFACE_DEF</a>,
44 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#ENUM_DEF">
45 * ENUM_DEF</a>,
46 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#METHOD_DEF">
47 * METHOD_DEF</a>,
48 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#CTOR_DEF">
49 * CTOR_DEF</a>,
50 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#VARIABLE_DEF">
51 * VARIABLE_DEF</a>,
52 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#RECORD_DEF">
53 * RECORD_DEF</a>,
54 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#COMPACT_CTOR_DEF">
55 * COMPACT_CTOR_DEF</a>.
56 * </li>
57 * </ul>
58 * <p>
59 * Parent is {@code com.puppycrawl.tools.checkstyle.TreeWalker}
60 * </p>
61 * <p>
62 * Violation Message Keys:
63 * </p>
64 * <ul>
65 * <li>
66 * {@code annotation.same.line}
67 * </li>
68 * </ul>
69 *
70 * @since 8.2
71 */
72 @StatelessCheck
73 public class AnnotationOnSameLineCheck extends AbstractCheck {
74
75 /** A key is pointing to the warning message text in "messages.properties" file. */
76 public static final String MSG_KEY_ANNOTATION_ON_SAME_LINE = "annotation.same.line";
77
78 @Override
79 public int[] getDefaultTokens() {
80 return new int[] {
81 TokenTypes.CLASS_DEF,
82 TokenTypes.INTERFACE_DEF,
83 TokenTypes.ENUM_DEF,
84 TokenTypes.METHOD_DEF,
85 TokenTypes.CTOR_DEF,
86 TokenTypes.VARIABLE_DEF,
87 TokenTypes.RECORD_DEF,
88 TokenTypes.COMPACT_CTOR_DEF,
89 };
90 }
91
92 @Override
93 public int[] getAcceptableTokens() {
94 return new int[] {
95 TokenTypes.CLASS_DEF,
96 TokenTypes.INTERFACE_DEF,
97 TokenTypes.ENUM_DEF,
98 TokenTypes.METHOD_DEF,
99 TokenTypes.CTOR_DEF,
100 TokenTypes.VARIABLE_DEF,
101 TokenTypes.PARAMETER_DEF,
102 TokenTypes.ANNOTATION_DEF,
103 TokenTypes.TYPECAST,
104 TokenTypes.LITERAL_THROWS,
105 TokenTypes.IMPLEMENTS_CLAUSE,
106 TokenTypes.TYPE_ARGUMENT,
107 TokenTypes.LITERAL_NEW,
108 TokenTypes.DOT,
109 TokenTypes.ANNOTATION_FIELD_DEF,
110 TokenTypes.RECORD_DEF,
111 TokenTypes.COMPACT_CTOR_DEF,
112 };
113 }
114
115 @Override
116 public int[] getRequiredTokens() {
117 return CommonUtil.EMPTY_INT_ARRAY;
118 }
119
120 @Override
121 public void visitToken(DetailAST ast) {
122 DetailAST nodeWithAnnotations = ast;
123 if (ast.getType() == TokenTypes.TYPECAST) {
124 nodeWithAnnotations = ast.findFirstToken(TokenTypes.TYPE);
125 }
126 DetailAST modifiersNode = nodeWithAnnotations.findFirstToken(TokenTypes.MODIFIERS);
127 if (modifiersNode == null) {
128 modifiersNode = nodeWithAnnotations.findFirstToken(TokenTypes.ANNOTATIONS);
129 }
130 if (modifiersNode != null) {
131 for (DetailAST annotationNode = modifiersNode.getFirstChild();
132 annotationNode != null;
133 annotationNode = annotationNode.getNextSibling()) {
134 if (annotationNode.getType() == TokenTypes.ANNOTATION
135 && !TokenUtil.areOnSameLine(annotationNode, getNextNode(annotationNode))) {
136 log(annotationNode, MSG_KEY_ANNOTATION_ON_SAME_LINE,
137 getAnnotationName(annotationNode));
138 }
139 }
140 }
141 }
142
143 /**
144 * Finds next node of ast tree.
145 *
146 * @param node current node
147 * @return node that is next to given
148 */
149 private static DetailAST getNextNode(DetailAST node) {
150 DetailAST nextNode = node.getNextSibling();
151 if (nextNode == null) {
152 nextNode = node.getParent().getNextSibling();
153 }
154 return nextNode;
155 }
156
157 /**
158 * Returns the name of the given annotation.
159 *
160 * @param annotation annotation node.
161 * @return annotation name.
162 */
163 private static String getAnnotationName(DetailAST annotation) {
164 DetailAST identNode = annotation.findFirstToken(TokenTypes.IDENT);
165 if (identNode == null) {
166 identNode = annotation.findFirstToken(TokenTypes.DOT).getLastChild();
167 }
168 return identNode.getText();
169 }
170
171 }