001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2014 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//////////////////////////////////////////////////////////////////////////////// 019package com.puppycrawl.tools.checkstyle.checks.modifier; 020 021import com.google.common.collect.Lists; 022import com.puppycrawl.tools.checkstyle.api.Check; 023import com.puppycrawl.tools.checkstyle.api.DetailAST; 024import com.puppycrawl.tools.checkstyle.api.TokenTypes; 025import java.util.Iterator; 026import java.util.List; 027 028/** 029 * <p> 030 * Checks that the order of modifiers conforms to the suggestions in the 031 * <a 032 * href="http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html"> 033 * Java Language specification, sections 8.1.1, 8.3.1 and 8.4.3</a>. 034 * The correct order is:</p> 035 036<ol> 037 <li><span class="code">public</span></li> 038 <li><span class="code">protected</span></li> 039 040 <li><span class="code">private</span></li> 041 <li><span class="code">abstract</span></li> 042 <li><span class="code">static</span></li> 043 <li><span class="code">final</span></li> 044 <li><span class="code">transient</span></li> 045 <li><span class="code">volatile</span></li> 046 047 <li><span class="code">synchronized</span></li> 048 <li><span class="code">native</span></li> 049 <li><span class="code">strictfp</span></li> 050</ol> 051 * In additional, modifiers are checked to ensure all annotations 052 * are declared before all other modifiers. 053 * <p> 054 * Rationale: Code is easier to read if everybody follows 055 * a standard. 056 * </p> 057 * <p> 058 * An example of how to configure the check is: 059 * </p> 060 * <pre> 061 * <module name="ModifierOrder"/> 062 * </pre> 063 * @author Lars Kühne 064 */ 065public class ModifierOrderCheck 066 extends Check 067{ 068 /** 069 * The order of modifiers as suggested in sections 8.1.1, 070 * 8.3.1 and 8.4.3 of the JLS. 071 */ 072 private static final String[] JLS_ORDER = 073 { 074 "public", "protected", "private", "abstract", "static", "final", 075 "transient", "volatile", "synchronized", "native", "strictfp", "default", 076 }; 077 078 @Override 079 public int[] getDefaultTokens() 080 { 081 return new int[] {TokenTypes.MODIFIERS}; 082 } 083 084 @Override 085 public void visitToken(DetailAST ast) 086 { 087 final List<DetailAST> mods = Lists.newArrayList(); 088 DetailAST modifier = ast.getFirstChild(); 089 while (modifier != null) { 090 mods.add(modifier); 091 modifier = modifier.getNextSibling(); 092 } 093 094 if (!mods.isEmpty()) { 095 final DetailAST error = checkOrderSuggestedByJLS(mods); 096 if (error != null) { 097 if (error.getType() == TokenTypes.ANNOTATION) { 098 log(error.getLineNo(), error.getColumnNo(), 099 "annotation.order", 100 error.getFirstChild().getText() 101 + error.getFirstChild().getNextSibling() 102 .getText()); 103 } 104 else { 105 log(error.getLineNo(), error.getColumnNo(), 106 "mod.order", error.getText()); 107 } 108 } 109 } 110 } 111 112 113 /** 114 * Checks if the modifiers were added in the order suggested 115 * in the Java language specification. 116 * 117 * @param modifiers 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> modifiers) 122 { 123 int i = 0; 124 DetailAST modifier; 125 final Iterator<DetailAST> it = modifiers.iterator(); 126 //No modifiers, no problems 127 if (!it.hasNext()) { 128 return null; 129 } 130 131 //Speed past all initial annotations 132 do { 133 modifier = it.next(); 134 } 135 while (it.hasNext() && (modifier.getType() == TokenTypes.ANNOTATION)); 136 137 //All modifiers are annotations, no problem 138 if (modifier.getType() == TokenTypes.ANNOTATION) { 139 return null; 140 } 141 142 while (i < JLS_ORDER.length) { 143 if (modifier.getType() == TokenTypes.ANNOTATION) { 144 //Annotation not at start of modifiers, bad 145 return modifier; 146 } 147 148 while ((i < JLS_ORDER.length) 149 && !JLS_ORDER[i].equals(modifier.getText())) 150 { 151 i++; 152 } 153 154 if (i == JLS_ORDER.length) { 155 //Current modifier is out of JLS order 156 return modifier; 157 } 158 else if (!it.hasNext()) { 159 //Reached end of modifiers without problem 160 return null; 161 } 162 else { 163 modifier = it.next(); 164 } 165 } 166 167 return modifier; 168 } 169}