Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
ModifierOrderCheck |
|
| 7.333333333333333;7.333 |
1 | //////////////////////////////////////////////////////////////////////////////// | |
2 | // checkstyle: Checks Java source code for adherence to a set of rules. | |
3 | // Copyright (C) 2001-2014 Oliver Burn | |
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 | package com.puppycrawl.tools.checkstyle.checks.modifier; | |
20 | ||
21 | import com.google.common.collect.Lists; | |
22 | import com.puppycrawl.tools.checkstyle.api.Check; | |
23 | import com.puppycrawl.tools.checkstyle.api.DetailAST; | |
24 | import com.puppycrawl.tools.checkstyle.api.TokenTypes; | |
25 | import java.util.Iterator; | |
26 | import java.util.List; | |
27 | ||
28 | /** | |
29 | * <p> | |
30 | * Checks that the order of modifiers conforms to the suggestions in the | |
31 | * <a | |
32 | * href="http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html"> | |
33 | * Java Language specification, sections 8.1.1, 8.3.1 and 8.4.3</a>. | |
34 | * The correct order is:</p> | |
35 | ||
36 | <ol> | |
37 | <li><span class="code">public</span></li> | |
38 | <li><span class="code">protected</span></li> | |
39 | ||
40 | <li><span class="code">private</span></li> | |
41 | <li><span class="code">abstract</span></li> | |
42 | <li><span class="code">static</span></li> | |
43 | <li><span class="code">final</span></li> | |
44 | <li><span class="code">transient</span></li> | |
45 | <li><span class="code">volatile</span></li> | |
46 | ||
47 | <li><span class="code">synchronized</span></li> | |
48 | <li><span class="code">native</span></li> | |
49 | <li><span class="code">strictfp</span></li> | |
50 | </ol> | |
51 | * In additional, modifiers are checked to ensure all annotations | |
52 | * are declared before all other modifiers. | |
53 | * <p> | |
54 | * Rationale: Code is easier to read if everybody follows | |
55 | * a standard. | |
56 | * </p> | |
57 | * <p> | |
58 | * An example of how to configure the check is: | |
59 | * </p> | |
60 | * <pre> | |
61 | * <module name="ModifierOrder"/> | |
62 | * </pre> | |
63 | * @author Lars Kühne | |
64 | */ | |
65 | 1 | public class ModifierOrderCheck |
66 | extends Check | |
67 | { | |
68 | /** | |
69 | * The order of modifiers as suggested in sections 8.1.1, | |
70 | * 8.3.1 and 8.4.3 of the JLS. | |
71 | */ | |
72 | 1 | private static final String[] JLS_ORDER = |
73 | { | |
74 | "public", "protected", "private", "abstract", "static", "final", | |
75 | "transient", "volatile", "synchronized", "native", "strictfp", | |
76 | }; | |
77 | ||
78 | @Override | |
79 | public int[] getDefaultTokens() | |
80 | { | |
81 | 1 | return new int[] {TokenTypes.MODIFIERS}; |
82 | } | |
83 | ||
84 | @Override | |
85 | public void visitToken(DetailAST aAST) | |
86 | { | |
87 | 32 | final List<DetailAST> mods = Lists.newArrayList(); |
88 | 32 | DetailAST modifier = aAST.getFirstChild(); |
89 | 70 | while (modifier != null) { |
90 | 38 | mods.add(modifier); |
91 | 38 | modifier = modifier.getNextSibling(); |
92 | } | |
93 | ||
94 | 32 | if (!mods.isEmpty()) { |
95 | 23 | final DetailAST error = checkOrderSuggestedByJLS(mods); |
96 | 23 | if (error != null) { |
97 | 6 | if (error.getType() == TokenTypes.ANNOTATION) { |
98 | 3 | log(error.getLineNo(), error.getColumnNo(), |
99 | "annotation.order", | |
100 | error.getFirstChild().getText() | |
101 | + error.getFirstChild().getNextSibling() | |
102 | .getText()); | |
103 | } | |
104 | else { | |
105 | 3 | log(error.getLineNo(), error.getColumnNo(), |
106 | "mod.order", error.getText()); | |
107 | } | |
108 | } | |
109 | } | |
110 | 32 | } |
111 | ||
112 | ||
113 | /** | |
114 | * Checks if the modifiers were added in the order suggested | |
115 | * in the Java language specification. | |
116 | * | |
117 | * @param aModifiers list of modifier AST tokens | |
118 | * @return null if the order is correct, otherwise returns the offending | |
119 | * * modifier AST. | |
120 | */ | |
121 | DetailAST checkOrderSuggestedByJLS(List<DetailAST> aModifiers) | |
122 | { | |
123 | 23 | int i = 0; |
124 | DetailAST modifier; | |
125 | 23 | final Iterator<DetailAST> it = aModifiers.iterator(); |
126 | //No modifiers, no problems | |
127 | 23 | if (!it.hasNext()) { |
128 | 0 | return null; |
129 | } | |
130 | ||
131 | //Speed past all initial annotations | |
132 | do { | |
133 | 25 | modifier = it.next(); |
134 | } | |
135 | 25 | while (it.hasNext() && (modifier.getType() == TokenTypes.ANNOTATION)); |
136 | ||
137 | //All modifiers are annotations, no problem | |
138 | 23 | if (modifier.getType() == TokenTypes.ANNOTATION) { |
139 | 1 | return null; |
140 | } | |
141 | ||
142 | 33 | while (i < JLS_ORDER.length) { |
143 | 33 | if (modifier.getType() == TokenTypes.ANNOTATION) { |
144 | //Annotation not at start of modifiers, bad | |
145 | 3 | return modifier; |
146 | } | |
147 | ||
148 | while ((i < JLS_ORDER.length) | |
149 | 120 | && !JLS_ORDER[i].equals(modifier.getText())) |
150 | { | |
151 | 90 | i++; |
152 | } | |
153 | ||
154 | 30 | if (i == JLS_ORDER.length) { |
155 | //Current modifier is out of JLS order | |
156 | 3 | return modifier; |
157 | } | |
158 | 27 | else if (!it.hasNext()) { |
159 | //Reached end of modifiers without problem | |
160 | 16 | return null; |
161 | } | |
162 | else { | |
163 | 11 | modifier = it.next(); |
164 | } | |
165 | } | |
166 | ||
167 | 0 | return modifier; |
168 | } | |
169 | } |