Skip to content

Commit 27d0021

Browse files
committed
Issue #78: extract: grab property info
1 parent f92362c commit 27d0021

File tree

3 files changed

+170
-6
lines changed

3 files changed

+170
-6
lines changed

config/sevntu_suppressions.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@
44
"http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
55

66
<suppressions>
7-
<suppress checks="MultipleStringLiteralsExtended" files=".*[\\/]src[\\/]test[\\/]"/>
7+
<suppress checks="MultipleStringLiteralsExtended" files="[\\/]ExtractInfoGeneratorTest.java$|.*[\\/]src[\\/]test[\\/]"/>
88
</suppressions>

config/suppressions.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
<suppress checks="MagicNumber" files=".*[\\/]src[\\/]test[\\/]"/>
1414
<suppress checks="AvoidStaticImport" files=".*[\\/]src[\\/]test[\\/]"/>
1515
<suppress checks="WriteTag" files=".*[\\/]src[\\/]test[\\/]"/>
16-
<suppress checks="MultipleStringLiterals" files=".*[\\/]src[\\/]test[\\/]"/>
16+
<suppress checks="MultipleStringLiterals" files="[\\/]ExtractInfoGeneratorTest.java$|.*[\\/]src[\\/]test[\\/]"/>
1717

1818
<suppress checks="AbstractClassName" files=".*[\\/]data[\\/]"/>
1919
</suppressions>

src/main/resources/com/github/checkstyle/regression/extract/ExtractInfoGeneratorTest.java

Lines changed: 168 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,26 @@
1919

2020
package com.puppycrawl.tools.checkstyle;
2121

22+
import java.beans.PropertyDescriptor;
2223
import java.io.File;
23-
import java.io.IOException;
2424
import java.nio.charset.Charset;
2525
import java.nio.file.Files;
2626
import java.nio.file.StandardOpenOption;
2727
import java.util.ArrayList;
2828
import java.util.Arrays;
2929
import java.util.Comparator;
3030
import java.util.List;
31+
import java.util.Set;
32+
import java.util.TreeSet;
3133

34+
import org.apache.commons.beanutils.PropertyUtils;
3235
import org.junit.Test;
3336

37+
import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
38+
import com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck;
39+
import com.puppycrawl.tools.checkstyle.checks.javadoc.AbstractJavadocCheck;
3440
import com.puppycrawl.tools.checkstyle.internal.CheckUtil;
41+
import com.puppycrawl.tools.checkstyle.internal.TestUtils;
3542
import com.puppycrawl.tools.checkstyle.utils.ModuleReflectionUtils;
3643

3744
/**
@@ -40,12 +47,57 @@
4047
* @author LuoLiangchen
4148
*/
4249
public class ExtractInfoGeneratorTest {
50+
/** Modules which do not have global properties to drop. */
51+
private static final List<String> XML_FILESET_LIST = Arrays.asList(
52+
"TreeWalker",
53+
"Checker",
54+
"Header",
55+
"Translation",
56+
"SeverityMatchFilter",
57+
"SuppressionFilter",
58+
"SuppressWarningsFilter",
59+
"BeforeExecutionExclusionFileFilter",
60+
"RegexpHeader",
61+
"RegexpOnFilename",
62+
"RegexpSingleline",
63+
"RegexpMultiline",
64+
"JavadocPackage",
65+
"NewlineAtEndOfFile",
66+
"UniqueProperties",
67+
"FileLength",
68+
"FileTabCharacter"
69+
);
70+
71+
/** Properties of abstract check. */
72+
private static final Set<String> CHECK_PROPERTIES = getProperties(AbstractCheck.class);
73+
74+
/** Properties of abstract Javadoc check. */
75+
private static final Set<String> JAVADOC_CHECK_PROPERTIES =
76+
getProperties(AbstractJavadocCheck.class);
77+
78+
/** Properties of abstract file-set check. */
79+
private static final Set<String> FILESET_PROPERTIES = getProperties(AbstractFileSetCheck.class);
80+
81+
/** Properties without document. */
82+
private static final List<String> UNDOCUMENTED_PROPERTIES = Arrays.asList(
83+
"Checker.classLoader",
84+
"Checker.classloader",
85+
"Checker.moduleClassLoader",
86+
"Checker.moduleFactory",
87+
"TreeWalker.classLoader",
88+
"TreeWalker.moduleFactory",
89+
"TreeWalker.cacheFile",
90+
"TreeWalker.upChild",
91+
"SuppressWithNearbyCommentFilter.fileContents",
92+
"SuppressionCommentFilter.fileContents"
93+
);
94+
4395
/**
4496
* Generates the extract info file named as "checkstyle_modules.json".
45-
* @throws IOException failure when generating the file
97+
* @throws Exception failure when generating the file
4698
*/
4799
@Test
48-
public void generateExtractInfoFile() throws IOException {
100+
public void generateExtractInfoFile() throws Exception {
49101
final List<Class<?>> modules = new ArrayList<>(CheckUtil.getCheckstyleModules());
50102
modules.sort(Comparator.comparing(Class::getSimpleName));
51103
final JsonUtil.JsonArray moduleJsonArray = new JsonUtil.JsonArray();
@@ -62,8 +114,10 @@ public void generateExtractInfoFile() throws IOException {
62114
* Creates Json object for a module from the module class.
63115
* @param clazz the given module class
64116
* @return the Json object describing the extract info of the module
117+
* @throws Exception failure when creating Json object
65118
*/
66-
private static JsonUtil.JsonObject createJsonObjectFromModuleClass(Class<?> clazz) {
119+
private static JsonUtil.JsonObject createJsonObjectFromModuleClass(Class<?> clazz)
120+
throws Exception {
67121
final JsonUtil.JsonObject object = new JsonUtil.JsonObject();
68122

69123
final String name = clazz.getSimpleName();
@@ -94,6 +148,116 @@ else if (ModuleReflectionUtils.isRootModule(clazz)) {
94148
object.add("interfaces", interfaces);
95149
object.add("hierarchies", hierarchies);
96150

151+
final JsonUtil.JsonArray properties = new JsonUtil.JsonArray();
152+
for (String propertyName : getNecessaryProperties(clazz)) {
153+
final JsonUtil.JsonObject property = new JsonUtil.JsonObject();
154+
property.addProperty("name", propertyName);
155+
Arrays.stream(PropertyUtils.getPropertyDescriptors(clazz))
156+
.filter(p -> p.getName().equals(propertyName))
157+
.map(PropertyDescriptor::getPropertyType)
158+
.map(Class::getSimpleName)
159+
.findAny()
160+
.ifPresent(type -> property.addProperty("type", type));
161+
properties.add(property);
162+
}
163+
object.add("properties", properties);
164+
97165
return object;
98166
}
167+
168+
/**
169+
* Gets the necessary properties of a checkstyle module.
170+
* Global properties and undocumented properties are not necessary for us.
171+
* @param clazz the class instance of the given module
172+
* @return a set of the necessary properties of the module
173+
* @throws Exception failure when getting properties
174+
*/
175+
// -@cs[CyclomaticComplexity] many different kinds of module
176+
private static Set<String> getNecessaryProperties(Class<?> clazz)
177+
throws Exception {
178+
final Set<String> properties = getProperties(clazz);
179+
if (hasParentModule(clazz.getSimpleName())) {
180+
if (AbstractJavadocCheck.class.isAssignableFrom(clazz)) {
181+
properties.removeAll(JAVADOC_CHECK_PROPERTIES);
182+
}
183+
else if (ModuleReflectionUtils.isCheckstyleCheck(clazz)) {
184+
properties.removeAll(CHECK_PROPERTIES);
185+
}
186+
}
187+
if (ModuleReflectionUtils.isFileSetModule(clazz)) {
188+
properties.removeAll(FILESET_PROPERTIES);
189+
190+
// override
191+
properties.add("fileExtensions");
192+
}
193+
194+
// undocumented properties are not necessary
195+
properties.removeIf(prop -> UNDOCUMENTED_PROPERTIES.contains(
196+
clazz.getSimpleName() + "." + prop));
197+
198+
final PackageObjectFactory factory = TestUtils.getPackageObjectFactory();
199+
final Object instance = factory.createModule(clazz.getSimpleName());
200+
201+
if (ModuleReflectionUtils.isCheckstyleCheck(clazz)) {
202+
final AbstractCheck check = (AbstractCheck) instance;
203+
204+
final int[] acceptableTokens = check.getAcceptableTokens();
205+
Arrays.sort(acceptableTokens);
206+
final int[] defaultTokens = check.getDefaultTokens();
207+
Arrays.sort(defaultTokens);
208+
final int[] requiredTokens = check.getRequiredTokens();
209+
Arrays.sort(requiredTokens);
210+
211+
if (!Arrays.equals(acceptableTokens, defaultTokens)
212+
|| !Arrays.equals(acceptableTokens, requiredTokens)) {
213+
properties.add("tokens");
214+
}
215+
}
216+
217+
if (AbstractJavadocCheck.class.isAssignableFrom(clazz)) {
218+
final AbstractJavadocCheck check = (AbstractJavadocCheck) instance;
219+
220+
final int[] acceptableJavadocTokens = check.getAcceptableJavadocTokens();
221+
Arrays.sort(acceptableJavadocTokens);
222+
final int[] defaultJavadocTokens = check.getDefaultJavadocTokens();
223+
Arrays.sort(defaultJavadocTokens);
224+
final int[] requiredJavadocTokens = check.getRequiredJavadocTokens();
225+
Arrays.sort(requiredJavadocTokens);
226+
227+
if (!Arrays.equals(acceptableJavadocTokens, defaultJavadocTokens)
228+
|| !Arrays.equals(acceptableJavadocTokens, requiredJavadocTokens)) {
229+
properties.add("javadocTokens");
230+
}
231+
}
232+
233+
return properties;
234+
}
235+
236+
/**
237+
* Gets the properties of a checkstyle module.
238+
* @param clazz the class instance of the given module
239+
* @return a set of the properties of the module
240+
*/
241+
private static Set<String> getProperties(Class<?> clazz) {
242+
final Set<String> result = new TreeSet<>();
243+
final PropertyDescriptor[] map = PropertyUtils.getPropertyDescriptors(clazz);
244+
245+
for (PropertyDescriptor p : map) {
246+
if (p.getWriteMethod() != null) {
247+
result.add(p.getName());
248+
}
249+
}
250+
251+
return result;
252+
}
253+
254+
/**
255+
* Checks whether a module has a parent that may contains global properties.
256+
* @param className the class name of given module
257+
* @return true if the module has a parent
258+
*/
259+
private static boolean hasParentModule(String className) {
260+
return !XML_FILESET_LIST.contains(className) && XML_FILESET_LIST.stream()
261+
.map(name -> name + "Check").noneMatch(name -> name.equals(className));
262+
}
99263
}

0 commit comments

Comments
 (0)