View Javadoc
1   ////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code for adherence to a set of rules.
3   // Copyright (C) 2001-2017 the original author or authors.
4   //
5   // This library is free software; you can redistribute it and/or
6   // modify it under the terms of the GNU Lesser General Public
7   // License as published by the Free Software Foundation; either
8   // version 2.1 of the License, or (at your option) any later version.
9   //
10  // This library is distributed in the hope that it will be useful,
11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  // Lesser General Public License for more details.
14  //
15  // You should have received a copy of the GNU Lesser General Public
16  // License along with this library; if not, write to the Free Software
17  // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  ////////////////////////////////////////////////////////////////////////////////
19  
20  package com.puppycrawl.tools.checkstyle.checks;
21  
22  import java.io.File;
23  import java.util.regex.Pattern;
24  
25  import com.puppycrawl.tools.checkstyle.FileStatefulCheck;
26  import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
27  import com.puppycrawl.tools.checkstyle.api.DetailAST;
28  import com.puppycrawl.tools.checkstyle.api.TokenTypes;
29  
30  /**
31   * Checks that the outer type name and the file name match.
32   * @author Oliver Burn
33   * @author maxvetrenko
34   */
35  @FileStatefulCheck
36  public class OuterTypeFilenameCheck extends AbstractCheck {
37      /**
38       * A key is pointing to the warning message text in "messages.properties"
39       * file.
40       */
41      public static final String MSG_KEY = "type.file.mismatch";
42  
43      /** Pattern matching any file extension with dot included. */
44      private static final Pattern FILE_EXTENSION_PATTERN = Pattern.compile("\\.[^.]*$");
45  
46      /** Indicates whether the first token has been seen in the file. */
47      private boolean seenFirstToken;
48  
49      /** Current file name. */
50      private String fileName;
51  
52      /** If file has public type. */
53      private boolean hasPublic;
54  
55      /** If first type has has same name as file. */
56      private boolean validFirst;
57  
58      /** Outer type with mismatched file name. */
59      private DetailAST wrongType;
60  
61      @Override
62      public int[] getDefaultTokens() {
63          return getRequiredTokens();
64      }
65  
66      @Override
67      public int[] getAcceptableTokens() {
68          return getRequiredTokens();
69      }
70  
71      @Override
72      public int[] getRequiredTokens() {
73          return new int[] {
74              TokenTypes.CLASS_DEF,
75              TokenTypes.INTERFACE_DEF,
76              TokenTypes.ENUM_DEF,
77              TokenTypes.ANNOTATION_DEF,
78          };
79      }
80  
81      @Override
82      public void beginTree(DetailAST rootAST) {
83          fileName = getFileName();
84          seenFirstToken = false;
85          validFirst = false;
86          hasPublic = false;
87          wrongType = null;
88      }
89  
90      @Override
91      public void visitToken(DetailAST ast) {
92          if (seenFirstToken) {
93              final DetailAST modifiers = ast.findFirstToken(TokenTypes.MODIFIERS);
94              if (modifiers.findFirstToken(TokenTypes.LITERAL_PUBLIC) != null
95                      && ast.getParent() == null) {
96                  hasPublic = true;
97              }
98          }
99          else {
100             final String outerTypeName = ast.findFirstToken(TokenTypes.IDENT).getText();
101 
102             if (fileName.equals(outerTypeName)) {
103                 validFirst = true;
104             }
105             else {
106                 wrongType = ast;
107             }
108         }
109         seenFirstToken = true;
110     }
111 
112     @Override
113     public void finishTree(DetailAST rootAST) {
114         if (!validFirst && !hasPublic && wrongType != null) {
115             log(wrongType.getLineNo(), MSG_KEY);
116         }
117     }
118 
119     /**
120      * Get source file name.
121      * @return source file name.
122      */
123     private String getFileName() {
124         String name = getFileContents().getFileName();
125         name = name.substring(name.lastIndexOf(File.separatorChar) + 1);
126         name = FILE_EXTENSION_PATTERN.matcher(name).replaceAll("");
127         return name;
128     }
129 }