From 5f68bb50fd191fec409f5edb90755a18fce3e0ac Mon Sep 17 00:00:00 2001
From: alexkravin
* Public members are not flagged if the name matches the public
@@ -47,7 +50,27 @@ import com.puppycrawl.tools.checkstyle.api.Utils;
*
- * Check also has an option making it less strict:
+ * Check also has options making it less strict:
+ *
+ * ignoreAnnotationCanonicalNames - the list of annotations canonical names
+ * which ignore variables in consideration, if user will provide short annotation name
+ * that type will match to any named the same type without consideration of package,
+ * list by default:
+ *
+ *
+ *
+ * For example such public field will be skipped by default value of list above: + *
+ *
+ *
+ *
* @org.junit.Rule
+ * public TemporaryFolder publicJUnitRule = new TemporaryFolder();
+ *
+ *
* allowPublicImmutableFields - which allows immutable fields be @@ -159,6 +182,50 @@ import com.puppycrawl.tools.checkstyle.api.Utils; * * *
+ *+ * To configure the Check passing fields annotated with + *
@com.annotation.CustomAnnotation: + * + *
+ * <module name="VisibilityModifier"> + * <property name="ignoreAnnotationCanonicalNames" value=" + * com.annotation.CustomAnnotation"/> + * </module> + *
+ *
+ *
+ *
+ * @com.annotation.CustomAnnotation
+ * String customAnnotated; // No warning
+ *
+ * @CustomAnnotation
+ * String shortCustomAnnotated; // No warning
+ *
+ *
+ * To configure the Check passing fields annotated with short annotation name + *
@CustomAnnotation: + * + *
+ * <module name="VisibilityModifier"> + * <property name="ignoreAnnotationCanonicalNames" + * value="CustomAnnotation"/> + * </module> + *
+ *
+ *
+ *
+ * @CustomAnnotation
+ * String customAnnotated; // No warning
+ *
+ * @com.annotation.CustomAnnotation
+ * String customAnnotated1; // No warning
+ *
+ * @mypackage.annotation.CustomAnnotation
+ * String customAnnotatedAnotherPackage; // another package but short name matches
+ * // so no violation
+ *
+ *
+ * This method will not look for imports or package + * statements to detect the passed in annotation. + *
+ * + *+ * To check if an AST contains a passed in annotation + * taking into account fully-qualified names + * (ex: java.lang.Override, Override) + * this method will need to be called twice. Once for each + * name given. + *
+ * + * @param variableDef {@link TokenTypes#VARIABLE_DEF variable def node}. + * @return the AST representing the first such annotation or null if + * no such annotation was found + */ + private DetailAST containsMatchingAnnotation(DetailAST variableDef) + { + DetailAST matchingAnnotation = null; + + final DetailAST holder = AnnotationUtility.getAnnotationHolder(variableDef); + + for (DetailAST child = holder.getFirstChild(); + child != null; child = child.getNextSibling()) + { + if (child.getType() == TokenTypes.ANNOTATION) { + final DetailAST at = child.getFirstChild(); + final String name = + FullIdent.createFullIdent(at.getNextSibling()).getText(); + if (ignoreAnnotationCanonicalNames.contains(name) + || ignoreAnnotationShortNames.contains(name)) + { + matchingAnnotation = child; + break; + } + } + } + + return matchingAnnotation; + } } diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/checks/design/VisibilityModifierCheckTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/checks/design/VisibilityModifierCheckTest.java index 2d9304232..f6446da8b 100644 --- a/src/test/java/com/puppycrawl/tools/checkstyle/checks/design/VisibilityModifierCheckTest.java +++ b/src/test/java/com/puppycrawl/tools/checkstyle/checks/design/VisibilityModifierCheckTest.java @@ -18,12 +18,13 @@ //////////////////////////////////////////////////////////////////////////////// package com.puppycrawl.tools.checkstyle.checks.design; +import static com.puppycrawl.tools.checkstyle.checks.design.VisibilityModifierCheck.MSG_KEY; + +import org.junit.Test; + import com.puppycrawl.tools.checkstyle.BaseCheckTestSupport; import com.puppycrawl.tools.checkstyle.Checker; import com.puppycrawl.tools.checkstyle.DefaultConfiguration; -import org.junit.Test; - -import static com.puppycrawl.tools.checkstyle.checks.design.VisibilityModifierCheck.MSG_KEY; public class VisibilityModifierCheckTest extends BaseCheckTestSupport @@ -180,4 +181,78 @@ public class VisibilityModifierCheckTest verify(checkConfig, getPath("InputImmutableStarImport2.java"), expected); } + @Test + public void testDefaultAnnotationPatterns() throws Exception + { + final DefaultConfiguration checkConfig = + createCheckConfig(VisibilityModifierCheck.class); + final String[] expected = { + "39:19: " + getCheckMessage(MSG_KEY, "customAnnotatedPublic"), + "42:12: " + getCheckMessage(MSG_KEY, "customAnnotatedPackage"), + "45:22: " + getCheckMessage(MSG_KEY, "customAnnotatedProtected"), + "47:19: " + getCheckMessage(MSG_KEY, "unannotatedPublic"), + "48:12: " + getCheckMessage(MSG_KEY, "unannotatedPackage"), + "49:22: " + getCheckMessage(MSG_KEY, "unannotatedProtected"), + }; + verify(checkConfig, getPath("AnnotatedVisibility.java"), expected); + } + + @Test + public void testCustomAnnotationPatterns() throws Exception + { + final DefaultConfiguration checkConfig = + createCheckConfig(VisibilityModifierCheck.class); + checkConfig.addAttribute("ignoreAnnotationCanonicalNames", + "com.puppycrawl.tools.checkstyle.AnnotatedVisibility.CustomAnnotation"); + final String[] expected = { + "15:28: " + getCheckMessage(MSG_KEY, "publicJUnitRule"), + "18:28: " + getCheckMessage(MSG_KEY, "fqPublicJUnitRule"), + "21:19: " + getCheckMessage(MSG_KEY, "googleCommonsAnnotatedPublic"), + "24:12: " + getCheckMessage(MSG_KEY, "googleCommonsAnnotatedPackage"), + "27:22: " + getCheckMessage(MSG_KEY, "googleCommonsAnnotatedProtected"), + "30:19: " + getCheckMessage(MSG_KEY, "fqGoogleCommonsAnnotatedPublic"), + "33:12: " + getCheckMessage(MSG_KEY, "fqGoogleCommonsAnnotatedPackage"), + "36:22: " + getCheckMessage(MSG_KEY, "fqGoogleCommonsAnnotatedProtected"), + "47:19: " + getCheckMessage(MSG_KEY, "unannotatedPublic"), + "48:12: " + getCheckMessage(MSG_KEY, "unannotatedPackage"), + "49:22: " + getCheckMessage(MSG_KEY, "unannotatedProtected"), + }; + verify(checkConfig, getPath("AnnotatedVisibility.java"), expected); + } + + @Test + public void testIgnoreAnnotationNoPattern() throws Exception + { + final DefaultConfiguration checkConfig = + createCheckConfig(VisibilityModifierCheck.class); + checkConfig.addAttribute("ignoreAnnotationCanonicalNames", ""); + final String[] expected = { + "15:28: " + getCheckMessage(MSG_KEY, "publicJUnitRule"), + "18:28: " + getCheckMessage(MSG_KEY, "fqPublicJUnitRule"), + "21:19: " + getCheckMessage(MSG_KEY, "googleCommonsAnnotatedPublic"), + "24:12: " + getCheckMessage(MSG_KEY, "googleCommonsAnnotatedPackage"), + "27:22: " + getCheckMessage(MSG_KEY, "googleCommonsAnnotatedProtected"), + "30:19: " + getCheckMessage(MSG_KEY, "fqGoogleCommonsAnnotatedPublic"), + "33:12: " + getCheckMessage(MSG_KEY, "fqGoogleCommonsAnnotatedPackage"), + "36:22: " + getCheckMessage(MSG_KEY, "fqGoogleCommonsAnnotatedProtected"), + "39:19: " + getCheckMessage(MSG_KEY, "customAnnotatedPublic"), + "42:12: " + getCheckMessage(MSG_KEY, "customAnnotatedPackage"), + "45:22: " + getCheckMessage(MSG_KEY, "customAnnotatedProtected"), + "47:19: " + getCheckMessage(MSG_KEY, "unannotatedPublic"), + "48:12: " + getCheckMessage(MSG_KEY, "unannotatedPackage"), + "49:22: " + getCheckMessage(MSG_KEY, "unannotatedProtected"), + }; + verify(checkConfig, getPath("AnnotatedVisibility.java"), expected); + } + + @Test + public void testIgnoreAnnotationSameName() throws Exception + { + final DefaultConfiguration checkConfig = + createCheckConfig(VisibilityModifierCheck.class); + final String[] expected = { + "10:28: " + getCheckMessage(MSG_KEY, "publicJUnitRule"), + }; + verify(checkConfig, getPath("AnnotatedVisibilitySameTypeName.java"), expected); + } } diff --git a/src/test/resources/com/puppycrawl/tools/checkstyle/AnnotatedVisibility.java b/src/test/resources/com/puppycrawl/tools/checkstyle/AnnotatedVisibility.java new file mode 100644 index 000000000..4064dd6d8 --- /dev/null +++ b/src/test/resources/com/puppycrawl/tools/checkstyle/AnnotatedVisibility.java @@ -0,0 +1,56 @@ +package com.puppycrawl.tools.checkstyle; + +import com.google.common.annotations.VisibleForTesting; + +import org.junit.Rule; +import org.junit.rules.TemporaryFolder; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +public class AnnotatedVisibility { + @Rule + public TemporaryFolder publicJUnitRule = new TemporaryFolder(); + + @org.junit.Rule + public TemporaryFolder fqPublicJUnitRule = new TemporaryFolder(); + + @VisibleForTesting + public String googleCommonsAnnotatedPublic; + + @VisibleForTesting + String googleCommonsAnnotatedPackage; + + @VisibleForTesting + protected String googleCommonsAnnotatedProtected; + + @com.google.common.annotations.VisibleForTesting + public String fqGoogleCommonsAnnotatedPublic; + + @com.google.common.annotations.VisibleForTesting + String fqGoogleCommonsAnnotatedPackage; + + @com.google.common.annotations.VisibleForTesting + protected String fqGoogleCommonsAnnotatedProtected; + + @CustomAnnotation + public String customAnnotatedPublic; + + @CustomAnnotation + String customAnnotatedPackage; + + @CustomAnnotation + protected String customAnnotatedProtected; + + public String unannotatedPublic; + String unannotatedPackage; + protected String unannotatedProtected; + private String unannotatedPrivate; + + @Retention(value=RetentionPolicy.RUNTIME) + @Target(value={ElementType.FIELD}) + public @interface CustomAnnotation { + } +} \ No newline at end of file diff --git a/src/test/resources/com/puppycrawl/tools/checkstyle/AnnotatedVisibilitySameTypeName.java b/src/test/resources/com/puppycrawl/tools/checkstyle/AnnotatedVisibilitySameTypeName.java new file mode 100644 index 000000000..900731836 --- /dev/null +++ b/src/test/resources/com/puppycrawl/tools/checkstyle/AnnotatedVisibilitySameTypeName.java @@ -0,0 +1,11 @@ +package com.puppycrawl.tools.checkstyle; + +import org.junit.rules.TemporaryFolder; + +import com.puppycrawl.tools.checkstyle.LocalAnnotations.Rule; + +public class AnnotatedVisibilitySameTypeName +{ + @Rule + public TemporaryFolder publicJUnitRule = new TemporaryFolder(); +} diff --git a/src/test/resources/com/puppycrawl/tools/checkstyle/LocalAnnotations.java b/src/test/resources/com/puppycrawl/tools/checkstyle/LocalAnnotations.java new file mode 100644 index 000000000..8ec685357 --- /dev/null +++ b/src/test/resources/com/puppycrawl/tools/checkstyle/LocalAnnotations.java @@ -0,0 +1,8 @@ +package com.puppycrawl.tools.checkstyle; + +public class LocalAnnotations +{ + public @interface Rule { + + } +} diff --git a/src/xdocs/config_design.xml b/src/xdocs/config_design.xml index 88559cd9a..389191940 100644 --- a/src/xdocs/config_design.xml +++ b/src/xdocs/config_design.xml @@ -13,9 +13,9 @@
- Checks visibility of class members. Only static final or immutable members
- may be public; other class members must be private unless the
- property protectedAllowed or packageAllowed is set.
+ Checks visibility of class members. Only static final, immutable or annotated
+ by specified annotation members may be public; other class members must be private
+ unless the property protectedAllowed or packageAllowed is set.
@@ -33,7 +33,12 @@ Rationale: Enforce encapsulation.
- Check also has an option making it less strict: + Check also has options making it less strict: +
++ ignoreAnnotationCanonicalNames - the list of annotations which ignore variables + in consideration. If user will provide short annotation name that type will match to any + named the same type without consideration of package
allowPublicImmutableFields - which allows immutable fields be declared as @@ -108,6 +113,12 @@ java.util.Locale, java.util.UUID, java.net.URL, java.net.URI, java.net.Inet4Address, java.net.Inet6Address, java.net.InetSocketAddress, +
+ To configure the Check passing fields annotated with @com.annotation.CustomAnnotation: +
++ Example of allowed field: +
++ To configure the Check passing fields annotated with @org.junit.Rule and + @com.google.common.annotations.VisibleForTesting annotations: +
++ Example of allowed fields: +
++ To configure the Check passing fields annotated with short annotation name: +
++ Example of allowed fields: +
+