Permalink
Browse files

Fixes sevntu-checkstyle#140: Updated ForbidCertainImportsCheck to let…

… user set excludes for forbidden imports
  • Loading branch information...
Daniil Yaroslavtsev
Daniil Yaroslavtsev committed Oct 14, 2013
1 parent 443d28b commit 56279c51bd6af72a876c55a39ef2cbc18189fce1
@@ -30,9 +30,10 @@ ConfusingConditionCheck.ignoreNullCaseInIf = Disable warnings for "if" if it exp
ConfusingConditionCheck.ignoreThrowInElse = Disable warnings for "if" if "else" block contain "throw".
ForbidCertainImports.name = Forbid Certain Imports
ForbidCertainImports.desc = Forbids certain imports usage in class.<br>Idea was taken from the similar check in Sonar project.<br><br>Parameters:<ol><li>Package regexp;</li><li>Forbidden imports regexp.</li></ol>Check operates with packages/imports text in string representation without "package"/"import" words and semicolons. You can be sure to write any regular expressions for package/imports text filtering.<br><br>Example of usage: to forbid to use "*.dao.*" packages in "*.ui.*" packages, you should use the following regular expressions:<br><br><dl><li>".+.ui..+" as Package name regexp;</li><li>".+.dao..+" as Forbidden imports regexp.</li></dl><br>By means of few instances of this check will be possible to check any number of rules.<br>
ForbidCertainImports.desc = Forbids certain imports usage in certain packages. <br/><br/>You can configure this check using following parameters:<ol><li>Package qualified name regexp;</li><li>Forbidden imports regexp;</li><li>Forbidden imports excludes regexp.</li></ol>This check reads packages and imports qualified names without words "package","import" and semicolons, so, please, do NOT include "package" or "import" words or semicolons into your regular expressions when configuring.<br/><br/>Real-life example of usage: forbid to use all "*.ui.*" packages in "*.dao.*" packages, but ignore all Exception imports (such as <b>org.springframework.dao.InvalidDataAccessResourceUsageException</b>). For doing that, you should use the following check parameters: <br/><br/><dl><li>Package name regexp = ".*ui.*"</li><li>Forbidden imports regexp = ".*dao.*"</li><li>Forbidden imports excludes regexp = "^.+Exception$"</li></dl><br/>By means of few instances of this check will be possible to cover any rules.<br/><br/>Author: <a href="https://github.com/daniilyar"> Daniil Yaroslavtsev</a>
ForbidCertainImports.packageNameRegexp = Package name regexp.
ForbidCertainImports.forbiddenImportRegexp = Forbidden import name regexp.
ForbidCertainImports.forbiddenImportsRegexp = Regexp for matching forbidden imports
ForbidCertainImports.forbiddenImportsExcludesRegexp = Regexp for excluding imports from checking
ForbidInstantiation.name = Forbid Instantiation
ForbidInstantiation.desc = Forbids instantiation of certain object types by their full classname.<br><p>For example:<br>"java.lang.NullPointerException" will forbid the NPE instantiation.</p><p>Note: className should to be full: use "java.lang.NullPointerException" instead of "NullpointerException".</p>
@@ -101,8 +101,11 @@
<property-metadata name="packageNameRegexp" datatype="Regex" default-value="">
<description>%ForbidCertainImports.packageNameRegexp</description>
</property-metadata>
<property-metadata name="forbiddenImportRegexp" datatype="Regex" default-value="">
<description>%ForbidCertainImports.forbiddenImportRegexp</description>
<property-metadata name="forbiddenImportsRegexp" datatype="Regex" default-value="">
<description>%ForbidCertainImports.forbiddenImportsRegexp</description>
</property-metadata>
<property-metadata name="forbiddenImportsExcludesRegexp" datatype="Regex" default-value="">
<description>%ForbidCertainImports.forbiddenImportsExcludesRegexp</description>
</property-metadata>
<message-key key="forbid.certain.imports" />
</rule-metadata>
@@ -26,28 +26,31 @@
import com.puppycrawl.tools.checkstyle.api.TokenTypes;
/**
* Forbids certain imports usage in class. <br>
* Idea was taken from the similar check in Sonar project. <br>
* <br>
* Parameters:
* Forbids certain imports usage in certain packages. <br/>
* <br/>
* You can configure this check using following parameters:
* <ol>
* <li>Package regexp;</li>
* <li>Forbidden imports regexp.</li>
* <li>Package qualified name regexp;</li>
* <li>Forbidden imports regexp;</li>
* <li>Forbidden imports excludes regexp.</li>
* </ol>
* Check operates with packages/imports text in string representation without
* "package"/"import" words and semicolons. You can be sure to write any regular
* expressions for package/imports text filtering. <br>
* <br>
* Example of usage: Forbid to use "*.ui.*" packages in "*.dao.*" packages: <br>
* <br>
* This check reads packages and imports qualified names without
* words "package","import" and semicolons, so, please, do NOT include "package" or
* "import" words or semicolons into your regular expressions when configuring.<br/>
* <br/>
* Real-life example of usage: forbid to use all "*.ui.*" packages in "*.dao.*" packages,
* but ignore all Exception imports (such as
* <b>org.springframework.dao.InvalidDataAccessResourceUsageException).
* For doing that, you should use following check parameters:</b> <br/>
* <br/>
* <dl>
* <li>Package name regexp = ".+.ui..+"</li>
* <li>Forbidden imports regexp = ".+.dao..+"</li>
* <li>Package name regexp = ".*ui.*"</li>
* <li>Forbidden imports regexp = ".*dao.*"</li>
* <li>Forbidden imports excludes regexp = "^.+Exception$"</li>
* </dl>
* <br>
* By means of few instances of this check will be possible to check any number
* of rules.<br>
* <br>
* <br/>
* By means of few instances of this check will be possible to cover any rules.<br/>
* <br/>
* @author <a href="mailto:Daniil.Yaroslavtsev@gmail.com"> Daniil
* Yaroslavtsev</a>
*/
@@ -71,6 +74,11 @@
*/
private Pattern mForbiddenImportsRegexp;
/**
* Pattern object is used to store the regexp for the forbidden import text
* checking.
*/
private Pattern mForbiddenImportsExcludesRegexp;
/**
* Boolean flag. True, if the current package text is being processed
@@ -101,28 +109,52 @@ public String getForbiddenImportRegexp()
/**
* Sets the regexp is currently used for the imports text checking.
* @param aForbiddenPackageNameRegexp
* @param aForbiddenImportsRegexp
* String contains a regex to set for the imports text checking.
*/
public void setForbiddenImportRegexp(String
aForbiddenPackageNameRegexp)
public void setForbiddenImportsRegexp(String
aForbiddenImportsRegexp)
{
if (aForbiddenPackageNameRegexp != null) {
mForbiddenImportsRegexp = Pattern
.compile(aForbiddenPackageNameRegexp);
if (aForbiddenImportsRegexp != null) {
mForbiddenImportsRegexp = Pattern.compile(aForbiddenImportsRegexp);
}
}
/**
* Gets the regexp for excluding imports from checking
* @return the regexp for excluding imports from checking.
*/
public String getForbiddenImportsExcludesRegexp()
{
return mForbiddenImportsExcludesRegexp.toString();
}
/**
* Sets the regexp for excluding imports from checking.
* @param aForbiddenImportsExcludedRegexp
* String contains a regexp for excluding imports from checking.
*/
public void setForbiddenImportsExcludesRegexp(String
aForbiddenImportsExcludedRegexp)
{
if (aForbiddenImportsExcludedRegexp != null) {
mForbiddenImportsExcludesRegexp = Pattern
.compile(aForbiddenImportsExcludedRegexp);
}
}
@Override
public int[] getDefaultTokens()
{
final int[] defaultTokens;
if (mPackageNamesRegexp != null && mForbiddenImportsRegexp != null) {
defaultTokens = new int[] {TokenTypes.PACKAGE_DEF,
TokenTypes.IMPORT, TokenTypes.LITERAL_NEW, };
if (mPackageNamesRegexp == null || mForbiddenImportsRegexp == null
|| mForbiddenImportsExcludesRegexp == null)
{
defaultTokens = new int[] {};
}
else {
defaultTokens = new int[] {};
defaultTokens = new int[] {TokenTypes.PACKAGE_DEF,
TokenTypes.IMPORT, TokenTypes.LITERAL_NEW, };
}
return defaultTokens;
}
@@ -138,27 +170,29 @@ public void visitToken(DetailAST aAst)
.matches();
}
break;
case TokenTypes.IMPORT:
if (mPackageMatches && mForbiddenImportsRegexp != null) {
if (mPackageMatches && mForbiddenImportsRegexp != null
&& mForbiddenImportsExcludesRegexp != null)
{
final String importText = getText(aAst);
final boolean importMatches = mForbiddenImportsRegexp.matcher(
importText).matches();
if (importMatches) {
log(aAst, importText);
if (isImportForbidden(importText)) {
if (isImportForbidden(importText)) {
log(aAst, importText);
}
}
}
break;
case TokenTypes.LITERAL_NEW:
if (mForbiddenImportsRegexp != null
&& mForbiddenImportsExcludesRegexp != null
&& aAst.findFirstToken(TokenTypes.DOT) != null
&& mPackageMatches)
{
final String importText = getText(aAst);
final boolean importMatches = mForbiddenImportsRegexp.matcher(
importText).matches();
if (importMatches) {
log(aAst, importText);
if (isImportForbidden(importText)) {
if (isImportForbidden(importText)) {
log(aAst, importText);
}
}
}
break;
@@ -173,6 +207,18 @@ public void visitToken(DetailAST aAst)
}
}
/**
* Checks if given import or inline qualified name
* matches 'include' and 'exclude' patterns
* @param aImportText package fully qualified name
* @return true is given import is forbidden in current
* classes package, false otherwise
*/
private boolean isImportForbidden(String aImportText)
{
return !mForbiddenImportsExcludesRegexp.matcher(aImportText).matches()
&& mForbiddenImportsRegexp.matcher(aImportText).matches();
}
/**
* Logs a warning message for given warn location.
@@ -193,7 +239,7 @@ private void log(DetailAST aNodeToWarn, String aImportText)
* @param aAST
* - DetailAST node is pointing to package or import definition
* (should be a PACKAGE_DEF or IMPORT type).
* @return The String representationpackage or import text without
* @return The fully qualified name of package or import without
* "package"/"import" words or semicolons.
*/
private static String getText(DetailAST aAST)
@@ -40,25 +40,45 @@ public void testNormalWork() throws Exception
String nameRegexp = ".+\\.old\\..+";
checkConfig.addAttribute("packageNameRegexp", nameRegexp);
checkConfig.addAttribute("forbiddenImportRegexp", importRegexp);
checkConfig.addAttribute("forbiddenImportsRegexp", importRegexp);
checkConfig.addAttribute("forbiddenImportsExcludesRegexp", "");
String[] expected = {
"3: " + getMessage(importRegexp,
"com.puppycrawl.tools.checkstyle.api.Check"),
"9: " + getMessage(importRegexp,
"com.puppycrawl.tools.checkstyle.api.Check"),
"21: " + getMessage(importRegexp,
"com.puppycrawl.tools.checkstyle.api.Check"),
"com.smth.tools.checkstyle.api.Smth"),
};
verify(checkConfig, getPath("InputForbidsCertainImports.java"), expected);
}
@Test
public void testNormalWorkWithExcludes() throws Exception
{
String importRegexp = ".+\\.api\\..+";
String nameRegexp = ".+\\.old\\..+";
checkConfig.addAttribute("packageNameRegexp", nameRegexp);
checkConfig.addAttribute("forbiddenImportsRegexp", importRegexp);
checkConfig.addAttribute("forbiddenImportsExcludesRegexp", "com.puppycrawl.+");
String[] expected = {
"21: " + getMessage(importRegexp,
"com.smth.tools.checkstyle.api.Smth"),
};
verify(checkConfig, getPath("InputForbidsCertainImports.java"), expected);
}
@Test
public void testEmptyImportsAndDefaultPackage() throws Exception
{
checkConfig.addAttribute("packageNameRegexp", ".+\\.old\\..+");
checkConfig.addAttribute("forbiddenImportRegexp", ".+\\.api\\..+");
checkConfig.addAttribute("forbiddenImportsRegexp", ".+\\.api\\..+");
checkConfig.addAttribute("forbiddenImportsExcludesRegexp", "");
String[] expected = {
};
@@ -70,7 +90,8 @@ public void testEmptyImportsAndDefaultPackage() throws Exception
public void testEmptyImportsAndDefaultPackageWithoutParams() throws Exception
{
checkConfig.addAttribute("packageNameRegexp", "");
checkConfig.addAttribute("forbiddenImportRegexp", "");
checkConfig.addAttribute("forbiddenImportsRegexp", "");
checkConfig.addAttribute("forbiddenImportsExcludesRegexp", "");
String[] expected = {
};
@@ -82,7 +103,8 @@ public void testEmptyImportsAndDefaultPackageWithoutParams() throws Exception
public void testImports() throws Exception
{
checkConfig.addAttribute("packageNameRegexp", "");
checkConfig.addAttribute("forbiddenImportRegexp", "");
checkConfig.addAttribute("forbiddenImportsRegexp", "");
checkConfig.addAttribute("forbiddenImportsExcludesRegexp", "");
String[] expected = {
};
@@ -18,7 +18,7 @@
public int a()
{
return 5;
Check check = new com.puppycrawl.tools.checkstyle.api.Check();
Smth smth = new com.smth.tools.checkstyle.api.Smth(); // forbidden!
}
}

0 comments on commit 56279c5

Please sign in to comment.