0
# Built-in Static Analysis Rules
1
2
Production-ready rules for detecting common issues in Velocity templates including best practices violations, design problems, and error-prone patterns. These rules are organized by category and ready for use in PMD rulesets.
3
4
## Capabilities
5
6
### Best Practices Rules
7
8
Rules that enforce Velocity template best practices and coding standards.
9
10
#### Avoid Reassigning Parameters
11
12
Detects reassignment of macro parameters, which can lead to confusion and unexpected behavior.
13
14
```java { .api }
15
/**
16
* Rule that detects reassignment of macro parameters.
17
* Parameter reassignment can make templates harder to understand and debug.
18
* Location: net.sourceforge.pmd.lang.vm.rule.bestpractices.AvoidReassigningParametersRule
19
*/
20
public class AvoidReassigningParametersRule extends AbstractVmRule {
21
// Implementation analyzes #set directives and macro parameter usage
22
// Reports violations when macro parameters are reassigned
23
}
24
```
25
26
**What it detects:**
27
- Reassignment of macro parameters using `#set` directive
28
- Modification of parameter values within macro body
29
- Potential confusion between parameter names and local variables
30
31
**Example violations:**
32
```velocity
33
#macro(processUser $userName $userAge)
34
#set($userName = "Modified") ## Violation: reassigning parameter
35
#set($userAge = $userAge + 1) ## Violation: reassigning parameter
36
<p>User: $userName, Age: $userAge</p>
37
#end
38
```
39
40
**Recommended fix:**
41
```velocity
42
#macro(processUser $userName $userAge)
43
#set($displayName = "Modified") ## Use different variable name
44
#set($calculatedAge = $userAge + 1) ## Use different variable name
45
<p>User: $displayName, Age: $calculatedAge</p>
46
#end
47
```
48
49
#### Unused Macro Parameter
50
51
Identifies macro parameters that are declared but never used, indicating potential dead code or missing implementation.
52
53
```java { .api }
54
/**
55
* Rule that detects unused macro parameters.
56
* Unused parameters suggest incomplete implementation or unnecessary complexity.
57
* Location: net.sourceforge.pmd.lang.vm.rule.bestpractices.UnusedMacroParameterRule
58
*/
59
public class UnusedMacroParameterRule extends AbstractVmRule {
60
// Implementation tracks macro parameter declarations and usage
61
// Reports violations for parameters that are never referenced
62
}
63
```
64
65
**What it detects:**
66
- Macro parameters that are declared but never referenced
67
- Parameters that may have been used in earlier template versions
68
- Potential API cleanup opportunities
69
70
**Example violations:**
71
```velocity
72
#macro(displayUser $userName $userAge $userEmail)
73
<p>Welcome $userName!</p>
74
<p>Age: $userAge</p>
75
## $userEmail is never used - violation
76
#end
77
```
78
79
**Recommended fix:**
80
```velocity
81
#macro(displayUser $userName $userAge) ## Remove unused parameter
82
<p>Welcome $userName!</p>
83
<p>Age: $userAge</p>
84
#end
85
```
86
87
### Design Rules
88
89
Rules that identify design issues and structural problems in Velocity templates.
90
91
#### Avoid Deeply Nested If Statements
92
93
Detects excessive nesting of if statements, which reduces readability and maintainability.
94
95
```java { .api }
96
/**
97
* Statistical rule that detects deeply nested if statements.
98
* Deep nesting makes templates difficult to read and maintain.
99
* Location: net.sourceforge.pmd.lang.vm.rule.design.AvoidDeeplyNestedIfStmtsRule
100
*/
101
public class AvoidDeeplyNestedIfStmtsRule extends AbstractStatisticalVmRule {
102
// Implementation tracks nesting depth of if statements
103
// Default threshold typically set to 3-4 levels
104
}
105
```
106
107
**What it detects:**
108
- If statements nested beyond configurable threshold (default: 3 levels)
109
- Complex conditional logic that may benefit from refactoring
110
- Templates that are difficult to test and maintain
111
112
**Example violations:**
113
```velocity
114
#if($user)
115
#if($user.isActive)
116
#if($user.hasPermission)
117
#if($user.inGroup) ## Violation: 4th level nesting
118
<p>User has access</p>
119
#end
120
#end
121
#end
122
#end
123
```
124
125
**Recommended fix:**
126
```velocity
127
#if($user && $user.isActive && $user.hasPermission && $user.inGroup)
128
<p>User has access</p>
129
#end
130
131
## Or use a macro to encapsulate complex logic
132
#macro(hasFullAccess $user)
133
#if($user && $user.isActive && $user.hasPermission && $user.inGroup)
134
true
135
#else
136
false
137
#end
138
#end
139
```
140
141
#### Collapsible If Statements
142
143
Identifies adjacent if statements that can be combined into a single conditional.
144
145
```java { .api }
146
/**
147
* Rule that detects if statements that can be collapsed into a single condition.
148
* Collapsible if statements indicate opportunities for simplification.
149
* Location: net.sourceforge.pmd.lang.vm.rule.design.CollapsibleIfStatementsRule
150
*/
151
public class CollapsibleIfStatementsRule extends AbstractVmRule {
152
// Implementation analyzes nested if statements with same conditional logic
153
// Reports violations when inner if can be combined with outer if
154
}
155
```
156
157
**What it detects:**
158
- Nested if statements that can be combined with logical operators
159
- Sequential if statements with related conditions
160
- Opportunities to simplify conditional logic
161
162
**Example violations:**
163
```velocity
164
#if($user)
165
#if($user.isActive) ## Violation: can be collapsed
166
<p>Active user: $user.name</p>
167
#end
168
#end
169
```
170
171
**Recommended fix:**
172
```velocity
173
#if($user && $user.isActive)
174
<p>Active user: $user.name</p>
175
#end
176
```
177
178
#### Excessive Template Length
179
180
Measures template length and flags templates that exceed reasonable size limits.
181
182
```java { .api }
183
/**
184
* Statistical rule that detects excessively long templates.
185
* Long templates are difficult to maintain and may indicate design issues.
186
* Location: net.sourceforge.pmd.lang.vm.rule.design.ExcessiveTemplateLengthRule
187
*/
188
public class ExcessiveTemplateLengthRule extends AbstractStatisticalVmRule {
189
// Implementation counts lines or AST nodes in template
190
// Default threshold typically set to 500-1000 lines
191
}
192
```
193
194
**What it detects:**
195
- Templates exceeding configurable line count threshold
196
- Templates that may benefit from decomposition
197
- Potential maintenance and testing challenges
198
199
**Configuration:**
200
- `maxLines`: Maximum allowed lines (default: 500)
201
- `countBlankLines`: Whether to include blank lines in count
202
203
**Recommended fixes:**
204
- Break large templates into smaller, focused templates
205
- Extract reusable sections into macros
206
- Use template inheritance or composition patterns
207
208
#### No Inline JavaScript
209
210
Detects inline JavaScript code within Velocity templates, promoting separation of concerns.
211
212
```java { .api }
213
/**
214
* Rule that detects inline JavaScript in Velocity templates.
215
* Inline JavaScript violates separation of concerns and complicates maintenance.
216
* Location: net.sourceforge.pmd.lang.vm.rule.design.NoInlineJavaScriptRule
217
*/
218
public class NoInlineJavaScriptRule extends AbstractVmRule {
219
// Implementation analyzes text content for JavaScript patterns
220
// Reports violations when <script> tags or JavaScript code detected
221
}
222
```
223
224
**What it detects:**
225
- `<script>` tags with JavaScript content
226
- Inline event handlers (`onclick`, `onload`, etc.)
227
- JavaScript code mixed with template markup
228
229
**Example violations:**
230
```velocity
231
<div onclick="alert('Hello')">Click me</div> ## Violation: inline JS
232
<script>
233
function doSomething() { ## Violation: inline script block
234
alert('Action performed');
235
}
236
</script>
237
```
238
239
**Recommended fix:**
240
```velocity
241
<div class="clickable-element">Click me</div>
242
## Move JavaScript to separate .js files
243
## Use CSS classes and external event handlers
244
```
245
246
#### No Inline Styles
247
248
Detects inline CSS styles within Velocity templates, promoting separation of concerns and maintainable styling.
249
250
```java { .api }
251
/**
252
* XPath-based rule that detects inline CSS styles in Velocity templates.
253
* Inline styles violate separation of concerns and complicate maintenance.
254
* Location: Implemented as XPath rule in category/vm/design.xml
255
*/
256
// XPath Rule: //Text[matches(@literal, "<[^>]+\s[sS][tT][yY][lL][eE]\s*=")]
257
// Rule Class: net.sourceforge.pmd.lang.rule.XPathRule
258
```
259
260
**What it detects:**
261
- `style` attributes on HTML elements
262
- Inline CSS declarations mixed with template markup
263
- CSS code that should be externalized to CSS files
264
265
**Example violations:**
266
```velocity
267
<div style="color: red; font-size: 14px;">Styled text</div> ## Violation: inline style
268
<p style="margin: 10px;">Content</p> ## Violation: inline style
269
<span style="background-color: #fff;">Text</span> ## Violation: inline style
270
```
271
272
**Recommended fix:**
273
```velocity
274
<div class="error-text">Styled text</div>
275
<p class="content-paragraph">Content</p>
276
<span class="highlighted-text">Text</span>
277
## Move styles to separate .css files
278
## Use CSS classes and external stylesheets
279
```
280
281
### Error-Prone Rules
282
283
Rules that detect patterns likely to cause runtime errors or unexpected behavior.
284
285
#### Empty Foreach Statement
286
287
Detects foreach loops with empty bodies, which may indicate incomplete implementation.
288
289
```java { .api }
290
/**
291
* Rule that detects empty foreach statements.
292
* Empty foreach loops suggest incomplete implementation or missing content.
293
* Location: net.sourceforge.pmd.lang.vm.rule.errorprone.EmptyForeachStmtRule
294
*/
295
public class EmptyForeachStmtRule extends AbstractVmRule {
296
// Implementation analyzes foreach statement bodies
297
// Reports violations when body contains no meaningful content
298
}
299
```
300
301
**What it detects:**
302
- Foreach loops with completely empty bodies
303
- Foreach loops containing only whitespace or comments
304
- Potentially incomplete loop implementations
305
306
**Example violations:**
307
```velocity
308
#foreach($item in $items)
309
## Empty loop body - violation
310
#end
311
312
#foreach($user in $users)
313
<!-- TODO: implement user display -->
314
## Only comments - violation
315
#end
316
```
317
318
**Recommended fix:**
319
```velocity
320
#foreach($item in $items)
321
<p>Item: $item</p>
322
#end
323
324
## Or remove the loop if not needed
325
```
326
327
#### Empty If Statement
328
329
Identifies if statements with empty bodies, indicating incomplete conditional logic.
330
331
```java { .api }
332
/**
333
* Rule that detects empty if statements.
334
* Empty if statements suggest incomplete implementation or unnecessary conditions.
335
* Location: net.sourceforge.pmd.lang.vm.rule.errorprone.EmptyIfStmtRule
336
*/
337
public class EmptyIfStmtRule extends AbstractVmRule {
338
// Implementation analyzes if statement bodies
339
// Reports violations when body contains no meaningful content
340
}
341
```
342
343
**What it detects:**
344
- If statements with completely empty bodies
345
- If statements containing only whitespace or comments
346
- Conditional logic that may be incomplete
347
348
**Example violations:**
349
```velocity
350
#if($user.isAdmin)
351
## Empty if body - violation
352
#end
353
354
#if($showSpecialContent)
355
<!-- Content will be added later -->
356
## Only comments - violation
357
#end
358
```
359
360
**Recommended fix:**
361
```velocity
362
#if($user.isAdmin)
363
<p>Admin panel access granted</p>
364
#end
365
366
## Or remove the condition if not needed
367
```
368
369
## Rule Configuration Examples
370
371
### PMD Ruleset Configuration
372
373
```xml
374
<?xml version="1.0"?>
375
<ruleset name="velocity-rules"
376
xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
377
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
378
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0
379
http://pmd.sourceforge.net/ruleset_2_0_0.xsd">
380
381
<description>Custom Velocity template rules</description>
382
383
<!-- Best Practices Rules -->
384
<rule ref="category/vm/bestpractices.xml/AvoidReassigningParameters"/>
385
<rule ref="category/vm/bestpractices.xml/UnusedMacroParameter"/>
386
387
<!-- Design Rules with Custom Configuration -->
388
<rule ref="category/vm/design.xml/ExcessiveTemplateLength">
389
<properties>
390
<property name="maxLines" value="300"/>
391
</properties>
392
</rule>
393
394
<rule ref="category/vm/design.xml/AvoidDeeplyNestedIfStmts">
395
<properties>
396
<property name="maxNesting" value="3"/>
397
</properties>
398
</rule>
399
400
<rule ref="category/vm/design.xml/CollapsibleIfStatements"/>
401
<rule ref="category/vm/design.xml/NoInlineJavaScript"/>
402
403
<!-- Error-Prone Rules -->
404
<rule ref="category/vm/errorprone.xml/EmptyIfStmt"/>
405
<rule ref="category/vm/errorprone.xml/EmptyForeachStmt"/>
406
</ruleset>
407
```
408
409
### Programmatic Rule Usage
410
411
```java
412
import net.sourceforge.pmd.PMD;
413
import net.sourceforge.pmd.PMDConfiguration;
414
import net.sourceforge.pmd.RuleSet;
415
import net.sourceforge.pmd.RuleSetFactory;
416
417
// Configure PMD for Velocity analysis
418
PMDConfiguration config = new PMDConfiguration();
419
config.setInputPaths("src/main/resources/templates");
420
config.setReportFormat("text");
421
422
// Load built-in Velocity rules
423
RuleSetFactory factory = new RuleSetFactory();
424
RuleSet ruleSet = factory.createRuleSet("category/vm/bestpractices.xml");
425
426
// Run analysis
427
PMD.runPMD(config);
428
```
429
430
### Custom Rule Integration
431
432
```java
433
import net.sourceforge.pmd.lang.vm.rule.AbstractVmRule;
434
435
// Custom rule extending built-in functionality
436
public class EnhancedUnusedParameterRule extends UnusedMacroParameterRule {
437
438
@Override
439
public Object visit(ASTReference node, Object data) {
440
// Call parent implementation
441
Object result = super.visit(node, data);
442
443
// Add custom analysis
444
analyzeReferencePattern(node, data);
445
446
return result;
447
}
448
449
private void analyzeReferencePattern(ASTReference node, Object data) {
450
// Custom pattern analysis
451
String refName = node.getRootString();
452
if (refName != null && refName.matches("^unused.*")) {
453
addViolation(data, node, "Reference suggests unused parameter: " + refName);
454
}
455
}
456
}
457
```
458
459
## Rule Suppression
460
461
### In-Template Suppression
462
463
```velocity
464
## Suppress specific rule for next directive
465
## NOPMD: AvoidReassigningParameters
466
#set($userName = "Modified")
467
468
## Suppress multiple rules
469
## NOPMD: EmptyIfStmt, UnusedMacroParameter
470
#if($condition)
471
#end
472
```
473
474
### External Suppression
475
476
```xml
477
<!-- PMD suppression file -->
478
<suppressions>
479
<suppress files="legacy-template.vm"
480
checks="ExcessiveTemplateLength"/>
481
<suppress files="generated-.*\.vm"
482
checks=".*"/>
483
</suppressions>
484
```