| 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 | } |