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.coding; 020 021import com.puppycrawl.tools.checkstyle.api.Check; 022import com.puppycrawl.tools.checkstyle.api.DetailAST; 023import com.puppycrawl.tools.checkstyle.api.FullIdent; 024import com.puppycrawl.tools.checkstyle.api.TokenTypes; 025import java.io.File; 026 027/** 028 * Ensures there is a package declaration. 029 * Rationale: Classes that live in the null package cannot be 030 * imported. Many novice developers are not aware of this. 031 * 032 * @author <a href="mailto:simon@redhillconsulting.com.au">Simon Harris</a> 033 * @author Oliver Burn 034 */ 035public final class PackageDeclarationCheck extends Check 036{ 037 /** is package defined. */ 038 private boolean mDefined; 039 /** whether to ignore the directory name matches the package. */ 040 private boolean mIgnoreDirectoryName; 041 042 /** 043 * Set whether to ignore checking the directory name. 044 * @param aValue the new value. 045 */ 046 public void setIgnoreDirectoryName(boolean aValue) 047 { 048 mIgnoreDirectoryName = aValue; 049 } 050 051 @Override 052 public int[] getDefaultTokens() 053 { 054 return new int[] {TokenTypes.PACKAGE_DEF}; 055 } 056 057 @Override 058 public int[] getRequiredTokens() 059 { 060 return getDefaultTokens(); 061 } 062 063 @Override 064 public void beginTree(DetailAST aAST) 065 { 066 mDefined = false; 067 } 068 069 @Override 070 public void finishTree(DetailAST aAST) 071 { 072 if (!mDefined) { 073 log(aAST.getLineNo(), "missing.package.declaration"); 074 } 075 } 076 077 @Override 078 public void visitToken(DetailAST aAST) 079 { 080 mDefined = true; 081 if (mIgnoreDirectoryName) { 082 return; 083 } 084 085 // Calculate the directory name, but stripping off the last 086 // part. 087 final String fname = getFileContents().getFilename(); 088 final int lastPos = fname.lastIndexOf(File.separatorChar); 089 final String dirname = fname.substring(0, lastPos); 090 091 // Convert the found package name into the expected directory name. 092 final DetailAST nameAST = aAST.getLastChild().getPreviousSibling(); 093 final FullIdent full = FullIdent.createFullIdent(nameAST); 094 final String expected = full.getText().replace('.', File.separatorChar); 095 096 // Finally see that the real directory ends with the expected directory 097 if (!dirname.endsWith(expected)) { 098 log(full.getLineNo(), 099 full.getColumnNo(), 100 "package.dir.mismatch", 101 expected); 102 } 103 } 104}