2222import java .io .IOException ;
2323import java .io .InputStream ;
2424import java .lang .reflect .Method ;
25+ import java .nio .charset .StandardCharsets ;
2526import java .util .ArrayList ;
2627import java .util .Arrays ;
2728import java .util .HashMap ;
2829import java .util .List ;
2930import java .util .Map ;
3031import java .util .Set ;
31- import java .util .regex .Pattern ;
3232import java .util .stream .Collectors ;
3333
3434import org .example .ModuleDetails ;
3535import org .example .ModulePropertyDetails ;
3636import org .example .ModuleType ;
37- import org .example .XMLReader ;
38- import org .reflections .Reflections ;
39- import org .reflections .scanners .ResourcesScanner ;
37+ import org .example .XMLMetaReader ;
4038import org .sonar .api .rule .RuleStatus ;
4139import org .sonar .api .server .debt .DebtRemediationFunction ;
4240import org .sonar .api .server .debt .internal .DefaultDebtRemediationFunction ;
4846import com .fasterxml .jackson .dataformat .yaml .YAMLFactory ;
4947
5048public class CheckstyleMetadata {
49+ private static final String CHECK_STRING = "Check" ;
50+ private static final String OPTION_STRING = "Option" ;
51+ private static final String COMMA_STRING = "," ;
52+ private static final int PARAM_TYPE_DB_COLUMN_TYPE_SIZE_LIMIT = 512 ;
5153 private final RulesDefinition .NewRepository repository ;
54+ private final Map <String , ModuleDetails > metadataRepo ;
5255
5356 public CheckstyleMetadata (RulesDefinition .NewRepository repository ) {
5457 this .repository = repository ;
58+ metadataRepo = new HashMap <>();
59+ new XMLMetaReader ().readAllModulesIncludingThirdPartyIfAny ()
60+ .forEach (moduleDetails -> { //NOSONAR
61+ metadataRepo .put (moduleDetails .getFullQualifiedName (),
62+ moduleDetails );
63+ });
5564 }
5665
5766 public void updateRulesWithMetadata () {
5867 repository .rules ().forEach (rule -> {
59- final String checkName = rule .key ().substring (rule .key ().lastIndexOf ('.' ) + 1 );
60- final ModuleDetails moduleDetails = loadMeta (checkName );
68+ final ModuleDetails moduleDetails = metadataRepo .get (rule .key ());
6169 if (moduleDetails != null ) {
6270 rule .setHtmlDescription (moduleDetails .getDescription ());
63- rule .setName (convertName (moduleDetails .getName ()));
71+ rule .setName (convertName (moduleDetails .getName () + CHECK_STRING ));
6472 rule .setInternalKey (convertInternalKey (moduleDetails ));
6573
6674 rule .params ().forEach (param -> { //NOSONAR
6775 if (!"tabWidth" .equals (param .key ())) {
68- constructParams (checkName , param ,
76+ constructParams (moduleDetails . getName () , param ,
6977 moduleDetails .getModulePropertyByKey (param .key ()));
7078 }
7179 }
@@ -76,17 +84,7 @@ public void updateRulesWithMetadata() {
7684
7785 public void createRulesWithMetadata () {
7886 final Set <String > existingChecks = repository .rules ().stream ()
79- .map (rule -> rule .key ().substring (rule .key ().lastIndexOf ('.' ) + 1 ))
80- .collect (Collectors .toSet ());
81- final Reflections reflections = new Reflections ("org.sonar.plugins.checkstyle.metadata" ,
82- new ResourcesScanner ());
83- final Set <String > fileNames = reflections .getResources (Pattern .compile (".*\\ .xml" ));
84- final Set <String > newChecks = fileNames .stream ()
85- .map (fileName -> { //NOSONAR
86- return fileName .substring (fileName .lastIndexOf ('/' ) + 1 ,
87- fileName .lastIndexOf ('.' ));
88- })
89- .filter (check -> !existingChecks .contains (check ))
87+ .map (RulesDefinition .NewRule ::key )
9088 .collect (Collectors .toSet ());
9189
9290 final Map <String , SonarRulePropertyLoader .AdditionalRuleProperties > additionalRuleData =
@@ -95,33 +93,45 @@ public void createRulesWithMetadata() {
9593 new DefaultDebtRemediationFunction (DebtRemediationFunction .Type .CONSTANT_ISSUE ,
9694 null , "0d 0h 5min" );
9795
98- for (String checkName : newChecks ) {
99- final ModuleDetails moduleDetails = loadMeta (checkName );
100- if (moduleDetails != null ) {
101- final SonarRulePropertyLoader .AdditionalRuleProperties additionalDetails =
102- additionalRuleData .get (checkName );
103- final RulesDefinition .NewRule rule =
104- repository .createRule (moduleDetails .getFullQualifiedName ());
105- rule .setHtmlDescription (moduleDetails .getDescription ())
106- .setName (convertName (moduleDetails .getName ()))
107- .setInternalKey (convertInternalKey (moduleDetails ))
108- .setDebtRemediationFunction (debtRemediationFunction )
109- .setSeverity ("MINOR" )
110- .setStatus (RuleStatus .READY );
111- final String tag = getRuleTag (moduleDetails .getFullQualifiedName (),
112- additionalDetails );
113- if (tag != null ) {
114- rule .setTags (tag );
115- }
116- if (isTemplateRule (moduleDetails .getFullQualifiedName ())) {
117- rule .setTemplate (true );
118- }
96+ metadataRepo .keySet ().stream ()
97+ .filter (check -> { //NOSONAR
98+ return !existingChecks .contains (check )
99+ && metadataRepo .get (check ).getModuleType () == ModuleType .CHECK
100+ // these checks are not available in checkstyle 8.35, these conditions
101+ // should be removed when upgrading to 8.36
102+ && !check .contains ("RecordTypeParameterNameCheck" )
103+ && !check .contains ("PatternVariableNameCheck" );
104+ })
105+ .forEach (newCheck -> {
106+ final ModuleDetails moduleDetails = metadataRepo .get (newCheck );
107+ if (moduleDetails != null ) {
108+ final SonarRulePropertyLoader .AdditionalRuleProperties additionalDetails =
109+ additionalRuleData .get (newCheck );
110+ final RulesDefinition .NewRule rule =
111+ repository .createRule (moduleDetails .getFullQualifiedName ());
112+ rule .setHtmlDescription (moduleDetails .getDescription ())
113+ .setName (convertName (moduleDetails .getName () + CHECK_STRING ))
114+ .setInternalKey (convertInternalKey (moduleDetails ))
115+ .setDebtRemediationFunction (debtRemediationFunction )
116+ .setSeverity ("MINOR" )
117+ .setStatus (RuleStatus .READY );
118+ final String tag = getRuleTag (moduleDetails .getFullQualifiedName (),
119+ additionalDetails );
120+ if (tag != null ) {
121+ rule .setTags (tag );
122+ }
123+ if (isTemplateRule (moduleDetails .getFullQualifiedName ())) {
124+ rule .setTemplate (true );
125+ }
119126
120- for (ModulePropertyDetails property : moduleDetails .getProperties ()) {
121- constructParams (checkName , rule .createParam (property .getName ()), property );
122- }
123- }
124- }
127+ for (ModulePropertyDetails property : moduleDetails .getProperties ()) {
128+ constructParams (moduleDetails .getName (),
129+ rule .createParam (property .getName ()),
130+ property );
131+ }
132+ }
133+
134+ });
125135 }
126136
127137 private Class <?> getClass (String checkName ) {
@@ -154,13 +164,36 @@ private void constructParams(String checkName, RulesDefinition.NewParam param,
154164 ModulePropertyDetails modulePropertyDetails ) {
155165 param .setDescription (modulePropertyDetails .getDescription ())
156166 .setDefaultValue (modulePropertyDetails .getDefaultValue ());
157- final String paramType = modulePropertyDetails .getType ();
158- if ("tokens" .equals (paramType ) || "javadocTokens" .equals (paramType )) {
159- final Object [] valuesArray = CheckUtil .getAcceptableTokens (checkName ).split ("," );
160- param .setType (RuleParamType .multipleListOfValues (Arrays .copyOf (
161- valuesArray , valuesArray .length , String [].class )));
167+ String paramType = modulePropertyDetails .getType ();
168+ if (modulePropertyDetails .getValidationType () != null
169+ && "tokenSet" .equals (modulePropertyDetails .getValidationType ())) {
170+ final Object [] valuesArray = CheckUtil .getAcceptableTokens (checkName )
171+ .split (COMMA_STRING );
172+ final String [] valuesStringArray = Arrays .copyOf (valuesArray , valuesArray .length ,
173+ String [].class );
174+
175+ int totalByteSize = 0 ;
176+ for (String x : valuesStringArray ) {
177+ final String tokenString = x + COMMA_STRING ;
178+ totalByteSize += tokenString .getBytes (StandardCharsets .UTF_8 ).length ;
179+ }
180+ totalByteSize += "'SINGLE_SELECT_LIST,multiple=true,values=\" "
181+ .getBytes (StandardCharsets .UTF_8 ).length ;
182+ // This check is required since the PARAM_TYPE column has size 512, and exceeding it
183+ // will result in an error in DB updates
184+ if (totalByteSize > PARAM_TYPE_DB_COLUMN_TYPE_SIZE_LIMIT ) {
185+ param .setType (RuleParamType .STRING );
186+ }
187+ else {
188+ param .setType (RuleParamType .multipleListOfValues (valuesStringArray ));
189+ }
162190 }
163- else if (paramType .endsWith ("Option" )) {
191+ else if (paramType .endsWith (OPTION_STRING )) {
192+ // the enum class names have been updated in later releases.
193+ // this condition should be removed when upgraded to 8.35
194+ if (paramType .contains ("AnnotationUseStyleCheck" )) {
195+ paramType = paramType .substring (0 , paramType .length () - OPTION_STRING .length ());
196+ }
164197 final Object [] valuesArray = getEnumValues (paramType ).toArray ();
165198 param .setType (RuleParamType .singleListOfValues (Arrays .copyOf (
166199 valuesArray , valuesArray .length , String [].class )));
@@ -212,24 +245,6 @@ private static String getRuleTag(String checkPackage,
212245 return additionalDetails ;
213246 }
214247
215- private ModuleDetails loadMeta (String checkName ) {
216- ModuleDetails moduleDetails = null ;
217- try {
218- final InputStream inputStream = getClass ()
219- .getResourceAsStream (checkName + ".xml" );
220- if (inputStream != null ) {
221- moduleDetails = new XMLReader ().read (inputStream , ModuleType .CHECK );
222- inputStream .close ();
223- }
224- }
225- catch (IOException ex ) {
226- throw new IllegalStateException ("exception occured during loadMeta of " + checkName ,
227- ex );
228- }
229-
230- return moduleDetails ;
231- }
232-
233248 public static boolean isSetter (Method method ) {
234249 return method .getName ().startsWith ("set" )
235250 && method .getParameterTypes ().length == 1 ;
@@ -242,7 +257,7 @@ public static boolean isSetter(Method method) {
242257 * @param name the name fetched from ModuleDetails
243258 * @return modifiedName
244259 */
245- private static String convertName (String name ) {
260+ public static String convertName (String name ) {
246261 final int capacity = 1024 ;
247262 final StringBuilder result = new StringBuilder (capacity );
248263 for (int i = 0 ; i < name .length (); i ++) {
@@ -254,15 +269,17 @@ private static String convertName(String name) {
254269 return result .toString ();
255270 }
256271
257- private static String convertInternalKey (ModuleDetails moduleDetails ) {
272+ public static String convertInternalKey (ModuleDetails moduleDetails ) {
258273 String result = "Checker/" ;
259- if ("Checker" .equals (moduleDetails .getParent ())) {
274+ if ("com.puppycrawl.tools.checkstyle. Checker" .equals (moduleDetails .getParent ())) {
260275 result += moduleDetails .getName ();
261276 }
262277 else {
263278 result += "TreeWalker/" + moduleDetails .getName ();
264279 }
280+ if (moduleDetails .getModuleType () == ModuleType .CHECK ) {
281+ result += CHECK_STRING ;
282+ }
265283 return result ;
266284 }
267-
268285}
0 commit comments