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}