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;
020
021import com.puppycrawl.tools.checkstyle.api.Check;
022import com.puppycrawl.tools.checkstyle.api.DetailAST;
023import com.puppycrawl.tools.checkstyle.api.TokenTypes;
024import java.io.File;
025
026/**
027 * Checks that the outer type name and the file name match.
028 * @author Oliver Burn
029 * @author maxvetrenko
030 */
031public class OuterTypeFilenameCheck extends Check
032{
033    /** indicates whether the first token has been seen in the file. */
034    private boolean seenFirstToken;
035
036    /** Current file name*/
037    private String fileName;
038
039    /** If file has public type*/
040    private boolean hasPublic;
041
042    /** If first type has has same name as file*/
043    private boolean validFirst;
044
045    /** Outer type with mismatched file name*/
046    private DetailAST wrongType;
047
048    @Override
049    public int[] getDefaultTokens()
050    {
051        return new int[] {
052            TokenTypes.CLASS_DEF, TokenTypes.INTERFACE_DEF,
053            TokenTypes.ENUM_DEF, TokenTypes.ANNOTATION_DEF,
054        };
055    }
056
057    @Override
058    public void beginTree(DetailAST ast)
059    {
060        fileName = getFileName();
061        seenFirstToken = false;
062        validFirst = false;
063        hasPublic = false;
064        wrongType = null;
065    }
066
067    @Override
068    public void visitToken(DetailAST ast)
069    {
070        final String outerTypeName = ast.findFirstToken(TokenTypes.IDENT).getText();
071        if (!seenFirstToken) {
072
073            if (fileName.equals(outerTypeName)) {
074                validFirst = true;
075            }
076            else {
077                wrongType = ast;
078            }
079        }
080        else {
081            final DetailAST modifiers = ast.findFirstToken(TokenTypes.MODIFIERS);
082            if (modifiers.findFirstToken(TokenTypes.LITERAL_PUBLIC) != null
083                    && ast.getParent() == null)
084            {
085                hasPublic = true;
086            }
087        }
088        seenFirstToken = true;
089    }
090
091    @Override
092    public void finishTree(DetailAST rootAST)
093    {
094        if (!(validFirst || hasPublic) && wrongType != null) {
095            log(wrongType.getLineNo(), "type.file.mismatch");
096        }
097    }
098
099    /**
100     * Get source file name.
101     * @return source file name.
102     */
103    private String getFileName()
104    {
105        String fname = getFileContents().getFilename();
106        fname = fname.substring(fname.lastIndexOf(File.separatorChar) + 1);
107        fname = fname.replaceAll("\\.[^\\.]*$", "");
108        return fname;
109    }
110}