Skip to content

Commit

Permalink
Issue #13758: Add pattern array converter for auto bean
Browse files Browse the repository at this point in the history
  • Loading branch information
Lmh-java committed Apr 12, 2024
1 parent e30260d commit 1a4fb0f
Show file tree
Hide file tree
Showing 13 changed files with 180 additions and 35 deletions.
Expand Up @@ -645,21 +645,6 @@
</details>
</checkerFrameworkError>

<checkerFrameworkError unstable="false">
<fileName>src/main/java/com/puppycrawl/tools/checkstyle/checks/metrics/AbstractClassCouplingCheck.java</fileName>
<specifier>methodref.receiver.bound</specifier>
<message>Incompatible receiver type</message>
<lineContent>.forEach(excludeClassesRegexps::add);</lineContent>
<details>
found : @GuardedBy List&lt;@GuardedBy Pattern&gt;
required: @GuardSatisfied List&lt;@GuardedBy Pattern&gt;
Consequence: method
@GuardedBy List&lt;@GuardedBy Pattern&gt;
is not a valid method reference for method in @GuardedBy List&lt;@GuardedBy Pattern&gt;
@GuardedBy boolean add(@GuardSatisfied List&lt;@GuardedBy Pattern&gt; this, @GuardedBy Pattern p0)
</details>
</checkerFrameworkError>

<checkerFrameworkError unstable="false">
<fileName>src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/AccessModifierOption.java</fileName>
<specifier>method.guarantee.violated</specifier>
Expand Down
2 changes: 2 additions & 0 deletions config/linkcheck-suppressions.txt
Expand Up @@ -35,6 +35,7 @@
<a href="AbstractNode.html#getDeclaredNamespaces(net.sf.saxon.om.NamespaceBinding%5B%5D)">AbstractNode.html#getDeclaredNamespaces(net.sf.saxon.om.NamespaceBinding%5B%5D)</a>: doesn't exist.
<a href="apidocs/com/puppycrawl/tools/checkstyle/AbstractAutomaticBean.OutputStreamOptions.html#%3Cinit%3E()">#%3Cinit%3E()</a>: doesn't exist.
<a href="apidocs/com/puppycrawl/tools/checkstyle/AbstractAutomaticBean.PatternConverter.html#%3Cinit%3E()">#%3Cinit%3E()</a>: doesn't exist.
<a href="apidocs/com/puppycrawl/tools/checkstyle/AbstractAutomaticBean.PatternArrayConverter.html#%3Cinit%3E()">#%3Cinit%3E()</a>: doesn't exist.
<a href="apidocs/com/puppycrawl/tools/checkstyle/AbstractAutomaticBean.RelaxedAccessModifierArrayConverter.html#%3Cinit%3E()">#%3Cinit%3E()</a>: doesn't exist.
<a href="apidocs/com/puppycrawl/tools/checkstyle/AbstractAutomaticBean.RelaxedStringArrayConverter.html#%3Cinit%3E()">#%3Cinit%3E()</a>: doesn't exist.
<a href="apidocs/com/puppycrawl/tools/checkstyle/AbstractAutomaticBean.ScopeConverter.html#%3Cinit%3E()">#%3Cinit%3E()</a>: doesn't exist.
Expand Down Expand Up @@ -801,6 +802,7 @@
<a href="apidocs/com/puppycrawl/tools/checkstyle/xpath/iterators/ReverseListIterator.html#%3Cinit%3E(java.util.Collection)">#%3Cinit%3E(java.util.Collection)</a>: doesn't exist.
<a href="apidocs/com/puppycrawl/tools/checkstyle/site/XdocsTemplateSink.CustomPrintWriter.html#%3Cinit%3E(java.io.Writer)">#%3Cinit%3E(java.io.Writer)</a>: doesn't exist.
<a href="com/puppycrawl/tools/checkstyle/AbstractAutomaticBean.OutputStreamOptions.html#%3Cinit%3E()">com/puppycrawl/tools/checkstyle/AbstractAutomaticBean.OutputStreamOptions.html#%3Cinit%3E()</a>: doesn't exist.
<a href="com/puppycrawl/tools/checkstyle/AbstractAutomaticBean.PatternArrayConverter.html#%3Cinit%3E()">com/puppycrawl/tools/checkstyle/AbstractAutomaticBean.PatternArrayConverter.html#%3Cinit%3E()</a>: doesn't exist.
<a href="com/puppycrawl/tools/checkstyle/AbstractAutomaticBean.PatternConverter.html#%3Cinit%3E()">com/puppycrawl/tools/checkstyle/AbstractAutomaticBean.PatternConverter.html#%3Cinit%3E()</a>: doesn't exist.
<a href="com/puppycrawl/tools/checkstyle/AbstractAutomaticBean.RelaxedAccessModifierArrayConverter.html#%3Cinit%3E()">com/puppycrawl/tools/checkstyle/AbstractAutomaticBean.RelaxedAccessModifierArrayConverter.html#%3Cinit%3E()</a>: doesn't exist.
<a href="com/puppycrawl/tools/checkstyle/AbstractAutomaticBean.RelaxedStringArrayConverter.html#%3Cinit%3E()">com/puppycrawl/tools/checkstyle/AbstractAutomaticBean.RelaxedStringArrayConverter.html#%3Cinit%3E()</a>: doesn't exist.
Expand Down
3 changes: 2 additions & 1 deletion config/pmd.xml
Expand Up @@ -316,7 +316,8 @@
<!-- Main has an annotated field for each command line option. This is by design. -->
<property name="violationSuppressXPath"
value="//ClassOrInterfaceDeclaration[@SimpleName='Checker']
| //ClassOrInterfaceDeclaration[@SimpleName='Main']"/>
| //ClassOrInterfaceDeclaration[@SimpleName='Main']
| //ClassOrInterfaceDeclaration[@SimpleName='ImportOrderCheck']"/>
</properties>
</rule>
<rule ref="category/java/design.xml/TooManyMethods">
Expand Down
Expand Up @@ -84,6 +84,9 @@ public enum OutputStreamOptions {
/** Comma separator for StringTokenizer. */
private static final String COMMA_SEPARATOR = ",";

/** Separator that splits multiple regex expression in a string. */
private static final String REGEX_SEPARATOR = COMMA_SEPARATOR;

/** The configuration of this bean. */
private Configuration configuration;

Expand Down Expand Up @@ -170,6 +173,7 @@ private static void registerIntegralTypes(ConvertUtilsBean cub) {
*/
private static void registerCustomTypes(ConvertUtilsBean cub) {
cub.register(new PatternConverter(), Pattern.class);
cub.register(new PatternArrayConverter(), Pattern[].class);
cub.register(new SeverityLevelConverter(), SeverityLevel.class);
cub.register(new ScopeConverter(), Scope.class);
cub.register(new UriConverter(), URI.class);
Expand Down Expand Up @@ -313,6 +317,22 @@ public Object convert(Class type, Object value) {

}

/** A converter that converts a string array to a pattern. */
private static final class PatternArrayConverter implements Converter {

@SuppressWarnings("unchecked")
@Override
public Object convert(Class type, Object value) {
final String plainString = value.toString();
final String[] patternStrings = plainString.split(REGEX_SEPARATOR);
final Pattern[] patterns = new Pattern[patternStrings.length];
for (int index = 0; index < patternStrings.length; index++) {
patterns[index] = CommonUtil.createPattern(patternStrings[index]);
}
return patterns;
}
}

/** A converter that converts strings to severity level. */
private static final class SeverityLevelConverter implements Converter {

Expand Down
Expand Up @@ -28,6 +28,8 @@
import com.puppycrawl.tools.checkstyle.api.DetailAST;
import com.puppycrawl.tools.checkstyle.api.FullIdent;
import com.puppycrawl.tools.checkstyle.api.TokenTypes;
import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
import com.puppycrawl.tools.checkstyle.utils.UnmodifiableCollectionUtil;

/**
* <p>
Expand Down Expand Up @@ -74,7 +76,7 @@
* (e.g. {@code /regexp/}). All type imports, which does not match any group, falls into an
* additional group, located at the end.
* Thus, the empty list of type groups (the default value) means one group for all type imports.
* Type is {@code java.util.regex.Pattern[]}.
* Type is {@code java.lang.String[]}.
* Default value is {@code ""}.
* </li>
* <li>
Expand Down Expand Up @@ -118,7 +120,7 @@
* an additional group, located at the end. Thus, the empty list of static groups (the default
* value) means one group for all static imports. This property has effect only when the property
* {@code option} is set to {@code top} or {@code bottom}.
* Type is {@code java.util.regex.Pattern[]}.
* Type is {@code java.lang.String[]}.
* Default value is {@code ""}.
* </li>
* <li>
Expand Down Expand Up @@ -186,7 +188,7 @@ public class ImportOrderCheck
* located at the end. Thus, the empty list of type groups (the default value) means one group
* for all type imports.
*/
private Pattern[] groups = EMPTY_PATTERN_ARRAY;
private String[] groups = CommonUtil.EMPTY_STRING_ARRAY;

/**
* Specify list of <b>static</b> import groups. Every group identified either by a common prefix
Expand All @@ -196,7 +198,7 @@ public class ImportOrderCheck
* static imports. This property has effect only when the property {@code option} is set to
* {@code top} or {@code bottom}.
*/
private Pattern[] staticGroups = EMPTY_PATTERN_ARRAY;
private String[] staticGroups = CommonUtil.EMPTY_STRING_ARRAY;

/**
* Control whether type import groups should be separated by, at least, one blank
Expand Down Expand Up @@ -262,6 +264,16 @@ public class ImportOrderCheck
*/
private ImportOrderOption option = ImportOrderOption.UNDER;

/**
* Complied array of patterns for property {@code groups}.
*/
private Pattern[] groupsReg = EMPTY_PATTERN_ARRAY;

/**
* Complied array of patterns for property {@code staticGroups}.
*/
private Pattern[] staticGroupsReg = EMPTY_PATTERN_ARRAY;

/**
* Setter to specify policy on the relative order between type imports and static imports.
*
Expand All @@ -284,7 +296,8 @@ public void setOption(String optionStr) {
* @since 3.2
*/
public void setGroups(String... packageGroups) {
groups = compilePatterns(packageGroups);
groups = UnmodifiableCollectionUtil.copyOfArray(packageGroups, packageGroups.length);
groupsReg = compilePatterns(packageGroups);
}

/**
Expand All @@ -299,7 +312,8 @@ public void setGroups(String... packageGroups) {
* @since 8.12
*/
public void setStaticGroups(String... packageGroups) {
staticGroups = compilePatterns(packageGroups);
staticGroups = UnmodifiableCollectionUtil.copyOfArray(packageGroups, packageGroups.length);
staticGroupsReg = compilePatterns(packageGroups);
}

/**
Expand Down Expand Up @@ -662,10 +676,10 @@ private static String getImportContainer(String qualifiedImportName) {
private int getGroupNumber(boolean isStatic, String name) {
final Pattern[] patterns;
if (isStatic) {
patterns = staticGroups;
patterns = staticGroupsReg;
}
else {
patterns = groups;
patterns = groupsReg;
}

int number = getGroupNumber(patterns, name);
Expand Down
Expand Up @@ -156,10 +156,8 @@ public final void setExcludedClasses(String... excludedClasses) {
*
* @param from array representing regular expressions of classes to ignore.
*/
public void setExcludeClassesRegexps(String... from) {
Arrays.stream(from)
.map(CommonUtil::createPattern)
.forEach(excludeClassesRegexps::add);
public void setExcludeClassesRegexps(Pattern... from) {
excludeClassesRegexps.addAll(Arrays.asList(from));
}

/**
Expand Down
Expand Up @@ -40,7 +40,7 @@
&lt;a href="https://en.wikipedia.org/wiki/ASCII#Order"&gt;ASCII sort order&lt;/a&gt;.
It affects both type imports and static imports.</description>
</property>
<property default-value="" name="groups" type="java.util.regex.Pattern[]">
<property default-value="" name="groups" type="java.lang.String[]">
<description>Specify list of &lt;b&gt;type import&lt;/b&gt; groups. Every group identified
either by a common prefix string, or by a regular expression enclosed in forward slashes
(e.g. {@code /regexp/}). All type imports, which does not match any group, falls into an
Expand Down Expand Up @@ -75,9 +75,7 @@
<description>Control whether
&lt;b&gt;static imports&lt;/b&gt; located at &lt;b&gt;top&lt;/b&gt; or &lt;b&gt;bottom&lt;/b&gt; are sorted within the group.</description>
</property>
<property default-value=""
name="staticGroups"
type="java.util.regex.Pattern[]">
<property default-value="" name="staticGroups" type="java.lang.String[]">
<description>Specify list of &lt;b&gt;static&lt;/b&gt; import groups. Every group
identified either by a common prefix string, or by a regular expression enclosed in forward
slashes (e.g. {@code /regexp/}). All static imports, which does not match any group, fall into
Expand Down
Expand Up @@ -23,7 +23,9 @@

import java.net.URI;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import org.apache.commons.beanutils.ConversionException;
import org.apache.commons.beanutils.ConvertUtilsBean;
Expand Down Expand Up @@ -278,6 +280,46 @@ public void testBeanConvertersUri3() {
}
}

@Test
public void testBeanConverterPatternArray1() throws Exception {
final ConverterBean bean = new ConverterBean();
final DefaultConfiguration config = new DefaultConfiguration("bean");
final String patternString = "^a*$,^b*$, ^c*$";
final List<String> expectedPatternString = Arrays.asList("^a*$", "^b*$", " ^c*$");
config.addProperty("patterns", patternString);
bean.configure(config);

assertWithMessage("invalid result")
.that(bean.patterns)
.hasLength(3);
assertWithMessage("invalid result")
.that(expectedPatternString)
.containsExactlyElementsIn(
Arrays.stream(bean.patterns)
.map(Pattern::pattern)
.collect(Collectors.toUnmodifiableList()));
}

@Test
public void testBeanConverterPatternArray2() throws Exception {
final ConverterBean bean = new ConverterBean();
final DefaultConfiguration config = new DefaultConfiguration("bean");
final String patternString = "^a*$";
final List<String> expectedPatternString = List.of("^a*$");
config.addProperty("patterns", patternString);
bean.configure(config);

assertWithMessage("invalid result")
.that(bean.patterns)
.hasLength(1);
assertWithMessage("invalid result")
.that(expectedPatternString)
.containsExactlyElementsIn(
Arrays.stream(bean.patterns)
.map(Pattern::pattern)
.collect(Collectors.toUnmodifiableList()));
}

private static final class ConvertUtilsBeanStub extends ConvertUtilsBean {

private int registerCount;
Expand Down Expand Up @@ -338,6 +380,7 @@ public static class ConverterBean extends AbstractAutomaticBean {
private Scope scope;
private URI uri;
private AccessModifierOption[] accessModifiers;
private Pattern[] patterns;

/**
* Setter for strings.
Expand Down Expand Up @@ -394,6 +437,15 @@ public void setAccessModifiers(AccessModifierOption... accessModifiers) {
accessModifiers.length);
}

/**
* Setter for patterns.
*
* @param patterns patterns
*/
public void setPatterns(Pattern... patterns) {
this.patterns = Arrays.copyOf(patterns, patterns.length);
}

@Override
protected void finishLocalSetup() {
// no code
Expand Down
Expand Up @@ -795,6 +795,27 @@ public void testTrimOption() throws Exception {
expected);
}

@Test
public void testUnmodifiableProperties() {
final ImportOrderCheck checkObj = new ImportOrderCheck();

final String[] expectedGroups = {"groups1", "groups2"};
final String[] expectedStaticGroups = {"static1", "static2"};
checkObj.setGroups(expectedGroups);
checkObj.setStaticGroups(expectedStaticGroups);

final String[] groups = TestUtil.getInternalState(checkObj, "groups");
final String[] staticGroups = TestUtil.getInternalState(checkObj, "staticGroups");
groups[0] = "modified";
staticGroups[0] = "modified";
assertWithMessage("Property 'groups' is not unmodifiable")
.that(expectedGroups[0])
.isNotEqualTo("modified");
assertWithMessage("Property 'staticGroups' is not unmodifiable")
.that(expectedStaticGroups[0])
.isNotEqualTo("modified");
}

/**
* Finding the appropriate input for testing the "lastImportStatic"
* field is challenging. Removing it from the reset process might
Expand Down
Expand Up @@ -371,4 +371,18 @@ public void testClearStatePackageName() throws Exception {
.isTrue();
}

/**
* Test [ClassName]::new expression. Such expression will be processed as a
* normal declaration of a new instance. We need to make sure this does not
*
* @throws Exception when code tested throws exception
*/
@Test
public void testLambdaNew() throws Exception {
final String[] expected = {};

verifyWithInlineConfigParser(
getPath("InputClassFanOutComplexityLambdaNew.java"), expected);
}

}
@@ -0,0 +1,40 @@
/*
ClassFanOutComplexity
max = 0
excludedClasses = (default)ArrayIndexOutOfBoundsException, ArrayList, Boolean, Byte, \
Character, Class, Collection, Deprecated, Deque, Double, DoubleStream, \
EnumSet, Exception, Float, FunctionalInterface, HashMap, HashSet, \
IllegalArgumentException, IllegalStateException, IndexOutOfBoundsException, \
IntStream, Integer, LinkedHashMap, LinkedHashSet, LinkedList, List, Long, \
LongStream, Map, NullPointerException, Object, Optional, OptionalDouble, \
OptionalInt, OptionalLong, Override, Queue, RuntimeException, SafeVarargs, \
SecurityException, Set, Short, SortedMap, SortedSet, Stream, String, \
StringBuffer, StringBuilder, SuppressWarnings, Throwable, TreeMap, TreeSet, \
UnsupportedOperationException, Void, boolean, byte, char, double, float, \
int, long, short, var, void
excludedPackages = (default)
*/

package com.puppycrawl.tools.checkstyle.checks.metrics.classfanoutcomplexity;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

class InputClassFanOutComplexityLambdaNew {
public void testMethod(Map<String, List<String>> entry) {
List<Constraint> constraints = new ArrayList<>();
String string = "";
entry.values().stream()
.flatMap(List::stream)
.map(Constraint::new)
.forEach(constraints::add);
}
}

class Constraint {
public Constraint(String data) {
}
}

0 comments on commit 1a4fb0f

Please sign in to comment.