1 ///////////////////////////////////////////////////////////////////////////////////////////////
2 // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
3 // Copyright (C) 2001-2025 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.naming;
21
22 import java.util.regex.Pattern;
23
24 import com.puppycrawl.tools.checkstyle.StatelessCheck;
25 import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
26 import com.puppycrawl.tools.checkstyle.api.DetailAST;
27 import com.puppycrawl.tools.checkstyle.api.FullIdent;
28 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
29
30 /**
31 * <div>
32 * Checks that package names conform to a specified pattern.
33 * </div>
34 *
35 * <p>
36 * The default value of {@code format} for module {@code PackageName} has been chosen to match
37 * the requirements in the
38 * <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-6.html#jls-6.5.3">
39 * Java Language specification</a>
40 * and the Sun coding conventions. However, both underscores and uppercase letters are rather
41 * uncommon, so most configurations should probably assign value
42 * {@code ^[a-z]+(\.[a-z][a-z0-9]*)*$} to {@code format} for module {@code PackageName}.
43 * </p>
44 *
45 * @since 3.0
46 */
47 @StatelessCheck
48 public class PackageNameCheck
49 extends AbstractCheck {
50
51 /**
52 * A key is pointing to the warning message text in "messages.properties"
53 * file.
54 */
55 public static final String MSG_KEY = "name.invalidPattern";
56
57 /** Control the pattern to match valid identifiers. */
58 // Uppercase letters seem rather uncommon, but they're allowed in
59 // https://docs.oracle.com/javase/specs/
60 // second_edition/html/packages.doc.html#40169
61 private Pattern format = Pattern.compile("^[a-z]+(\\.[a-zA-Z_]\\w*)*$");
62
63 /**
64 * Setter to control the pattern to match valid identifiers.
65 *
66 * @param pattern the new pattern
67 * @since 3.0
68 */
69 public void setFormat(Pattern pattern) {
70 format = pattern;
71 }
72
73 @Override
74 public int[] getDefaultTokens() {
75 return getRequiredTokens();
76 }
77
78 @Override
79 public int[] getAcceptableTokens() {
80 return getRequiredTokens();
81 }
82
83 @Override
84 public int[] getRequiredTokens() {
85 return new int[] {TokenTypes.PACKAGE_DEF};
86 }
87
88 @Override
89 public void visitToken(DetailAST ast) {
90 final DetailAST nameAST = ast.getLastChild().getPreviousSibling();
91 final FullIdent full = FullIdent.createFullIdent(nameAST);
92 if (!format.matcher(full.getText()).find()) {
93 log(full.getDetailAst(),
94 MSG_KEY,
95 full.getText(),
96 format.pattern());
97 }
98 }
99
100 }