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.puppycrawl.tools.checkstyle.api.Check; 022import com.puppycrawl.tools.checkstyle.api.DetailAST; 023import com.puppycrawl.tools.checkstyle.api.ScopeUtils; 024import com.puppycrawl.tools.checkstyle.api.TokenTypes; 025 026/** 027 * Checks for redundant modifiers in interface and annotation definitions. 028 * Also checks for redundant final modifiers on methods of final classes. 029 * 030 * @author lkuehne 031 */ 032public class RedundantModifierCheck 033 extends Check 034{ 035 @Override 036 public int[] getDefaultTokens() 037 { 038 return new int[] { 039 TokenTypes.METHOD_DEF, 040 TokenTypes.VARIABLE_DEF, 041 TokenTypes.ANNOTATION_FIELD_DEF, 042 TokenTypes.INTERFACE_DEF, 043 }; 044 } 045 046 @Override 047 public int[] getRequiredTokens() 048 { 049 return new int[] {}; 050 } 051 052 @Override 053 public void visitToken(DetailAST aAST) 054 { 055 if (TokenTypes.INTERFACE_DEF == aAST.getType()) { 056 final DetailAST modifiers = 057 aAST.findFirstToken(TokenTypes.MODIFIERS); 058 if (null != modifiers) { 059 for (final int tokenType : new int[] { 060 TokenTypes.LITERAL_STATIC, 061 TokenTypes.ABSTRACT, }) 062 { 063 final DetailAST modifier = 064 modifiers.findFirstToken(tokenType); 065 if (null != modifier) { 066 log(modifier.getLineNo(), modifier.getColumnNo(), 067 "redundantModifier", modifier.getText()); 068 } 069 } 070 } 071 } 072 else if (ScopeUtils.inInterfaceOrAnnotationBlock(aAST)) { 073 final DetailAST modifiers = 074 aAST.findFirstToken(TokenTypes.MODIFIERS); 075 076 DetailAST modifier = modifiers.getFirstChild(); 077 while (modifier != null) { 078 079 // javac does not allow final or static in interface methods 080 // order annotation fields hence no need to check that this 081 // is not a method or annotation field 082 083 final int type = modifier.getType(); 084 if ((type == TokenTypes.LITERAL_PUBLIC) 085 || ((type == TokenTypes.LITERAL_STATIC) 086 && aAST.getType() != TokenTypes.METHOD_DEF) 087 || (type == TokenTypes.ABSTRACT) 088 || (type == TokenTypes.FINAL)) 089 { 090 log(modifier.getLineNo(), modifier.getColumnNo(), 091 "redundantModifier", modifier.getText()); 092 break; 093 } 094 095 modifier = modifier.getNextSibling(); 096 } 097 } 098 else if (aAST.getType() == TokenTypes.METHOD_DEF) { 099 final DetailAST modifiers = 100 aAST.findFirstToken(TokenTypes.MODIFIERS); 101 // private method? 102 boolean checkFinal = 103 modifiers.branchContains(TokenTypes.LITERAL_PRIVATE); 104 // declared in a final class? 105 DetailAST parent = aAST.getParent(); 106 while (parent != null) { 107 if (parent.getType() == TokenTypes.CLASS_DEF) { 108 final DetailAST classModifiers = 109 parent.findFirstToken(TokenTypes.MODIFIERS); 110 checkFinal |= 111 classModifiers.branchContains(TokenTypes.FINAL); 112 break; 113 } 114 parent = parent.getParent(); 115 } 116 if (checkFinal) { 117 DetailAST modifier = modifiers.getFirstChild(); 118 while (modifier != null) { 119 final int type = modifier.getType(); 120 if (type == TokenTypes.FINAL) { 121 log(modifier.getLineNo(), modifier.getColumnNo(), 122 "redundantModifier", modifier.getText()); 123 break; 124 } 125 modifier = modifier.getNextSibling(); 126 } 127 } 128 } 129 } 130}