001: ////////////////////////////////////////////////////////////////////////////////
002: // checkstyle: Checks Java source code for adherence to a set of rules.
003: // Copyright (C) 2001-2007 Oliver Burn
004: //
005: // This library is free software; you can redistribute it and/or
006: // modify it under the terms of the GNU Lesser General Public
007: // License as published by the Free Software Foundation; either
008: // version 2.1 of the License, or (at your option) any later version.
009: //
010: // This library is distributed in the hope that it will be useful,
011: // but WITHOUT ANY WARRANTY; without even the implied warranty of
012: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: // Lesser General Public License for more details.
014: //
015: // You should have received a copy of the GNU Lesser General Public
016: // License along with this library; if not, write to the Free Software
017: // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018: ////////////////////////////////////////////////////////////////////////////////
019: package com.puppycrawl.tools.checkstyle.checks.modifier;
020:
021: import antlr.collections.AST;
022:
023: import java.util.List;
024: import java.util.ArrayList;
025: import java.util.Iterator;
026:
027: import com.puppycrawl.tools.checkstyle.api.Check;
028: import com.puppycrawl.tools.checkstyle.api.TokenTypes;
029: import com.puppycrawl.tools.checkstyle.api.DetailAST;
030:
031: /**
032: * <p>
033: * Checks that the order of modifiers conforms to the suggestions in the
034: * <a
035: * href="http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html">
036: * Java Language specification, sections 8.1.1, 8.3.1 and 8.4.3</a>.
037: * The correct order is:</p>
038:
039: <ol>
040: <li><span class="code">public</span></li>
041: <li><span class="code">protected</span></li>
042:
043: <li><span class="code">private</span></li>
044: <li><span class="code">abstract</span></li>
045: <li><span class="code">static</span></li>
046: <li><span class="code">final</span></li>
047: <li><span class="code">transient</span></li>
048: <li><span class="code">volatile</span></li>
049:
050: <li><span class="code">synchronized</span></li>
051: <li><span class="code">native</span></li>
052: <li><span class="code">strictfp</span></li>
053: </ol>
054: * In additional, modifiers are checked to ensure all annotations
055: * are declared before all other modifiers.
056: * <p>
057: * Rationale: Code is easier to read if everybody follows
058: * a standard.
059: * </p>
060: * <p>
061: * An example of how to configure the check is:
062: * </p>
063: * <pre>
064: * <module name="ModifierOrder"/>
065: * </pre>
066: * @author Lars Kühne
067: */
068: public class ModifierOrderCheck extends Check {
069: /**
070: * The order of modifiers as suggested in sections 8.1.1,
071: * 8.3.1 and 8.4.3 of the JLS.
072: */
073: private static final String[] JLS_ORDER = { "public", "protected",
074: "private", "abstract", "static", "final", "transient",
075: "volatile", "synchronized", "native", "strictfp", };
076:
077: /** {@inheritDoc} */
078: public int[] getDefaultTokens() {
079: return new int[] { TokenTypes.MODIFIERS };
080: }
081:
082: /** {@inheritDoc} */
083: public void visitToken(DetailAST aAST) {
084: final List mods = new ArrayList();
085: AST modifier = aAST.getFirstChild();
086: while (modifier != null) {
087: mods.add(modifier);
088: modifier = modifier.getNextSibling();
089: }
090:
091: if (!mods.isEmpty()) {
092: final DetailAST error = checkOrderSuggestedByJLS(mods);
093: if (error != null) {
094: if (error.getType() == TokenTypes.ANNOTATION) {
095: log(error.getLineNo(), error.getColumnNo(),
096: "annotation.order", error.getFirstChild()
097: .getText()
098: + error.getFirstChild()
099: .getNextSibling().getText());
100: } else {
101: log(error.getLineNo(), error.getColumnNo(),
102: "mod.order", error.getText());
103: }
104: }
105: }
106: }
107:
108: /**
109: * Checks if the modifiers were added in the order suggested
110: * in the Java language specification.
111: *
112: * @param aModifiers list of modifier AST tokens
113: * @return null if the order is correct, otherwise returns the offending
114: * * modifier AST.
115: */
116: DetailAST checkOrderSuggestedByJLS(List aModifiers) {
117: int i = 0;
118: DetailAST modifier;
119: final Iterator it = aModifiers.iterator();
120: //No modifiers, no problems
121: if (!it.hasNext()) {
122: return null;
123: }
124:
125: //Speed past all initial annotations
126: do {
127: modifier = (DetailAST) it.next();
128: } while (it.hasNext()
129: && (modifier.getType() == TokenTypes.ANNOTATION));
130:
131: //All modifiers are annotations, no problem
132: if (modifier.getType() == TokenTypes.ANNOTATION) {
133: return null;
134: }
135:
136: while (i < JLS_ORDER.length) {
137: if (modifier.getType() == TokenTypes.ANNOTATION) {
138: //Annotation not at start of modifiers, bad
139: return modifier;
140: }
141:
142: while ((i < JLS_ORDER.length)
143: && !JLS_ORDER[i].equals(modifier.getText())) {
144: i++;
145: }
146:
147: if (i == JLS_ORDER.length) {
148: //Current modifier is out of JLS order
149: return modifier;
150: } else if (!it.hasNext()) {
151: //Reached end of modifiers without problem
152: return null;
153: } else {
154: modifier = (DetailAST) it.next();
155: }
156: }
157:
158: return modifier;
159: }
160: }
|