SONARJAVA-6197 S1451 should not fail at analysis time when an empty headerFormat rule property marked as a regular expression is provided#5577
Conversation
SummaryWhat changed: Modified S1451 (FileHeaderCheck) to gracefully handle empty Why: The original code tried to compile empty headerFormat strings as regex patterns when isRegularExpression=true, which caused an IllegalArgumentException. The fix detects empty headers upfront and treats them as no-header-required (equivalent to expectedLines=[]), skipping regex compilation entirely. The fix: Added an early check in What reviewers should knowStart here: Look at Understanding the issue:
Test coverage: New tests verify the fix works for both regex and non-regex modes with empty headers:
Minor change: Removed unnecessary blank line in
|
There was a problem hiding this comment.
The fix is correct and covers both sides of the bug: the crash when empty regex is compiled, and a pre-existing false-positive where a plain-text empty header was split to [""] rather than [], causing files like Class5.java to get incorrectly flagged. One design concern is worth noting below.
| if (headerFormat.isEmpty()) { | ||
| expectedLines = new String[]{}; | ||
| isRegularExpression = false; |
There was a problem hiding this comment.
isRegularExpression is a @RuleProperty-annotated public field set by the SonarQube framework to represent user configuration. Mutating it inside setContext() means the field no longer reflects the user's intent after the first file is scanned.
In practice this is harmless — the isEmpty() guard is re-evaluated on every call so the mutation is always re-applied for empty headers. But if the framework ever inspects or logs the field value after scanning (for diagnostics or rule-parameter serialization), it will see false even when the user explicitly set true.
A cleaner approach: replace the mutation with a local boolean that shadows the field for the duration of the call:
boolean effectiveRegex = isRegularExpression;
if (headerFormat.isEmpty()) {
expectedLines = new String[]{};
effectiveRegex = false;
} else if (isRegularExpression) {
...
}This keeps rule-property state immutable and makes the intent explicit.
| if (headerFormat.isEmpty()) { | |
| expectedLines = new String[]{}; | |
| isRegularExpression = false; | |
| if (headerFormat.isEmpty()) { | |
| expectedLines = new String[]{}; | |
| } else { | |
| if (isRegularExpression) { | |
| if (searchPattern == null) { | |
| try { | |
| searchPattern = Pattern.compile(getHeaderFormat(), Pattern.DOTALL); | |
| } catch (IllegalArgumentException e) { | |
| throw new IllegalArgumentException("[" + getClass().getSimpleName() + "] Unable to compile the regular expression: " + headerFormat, e); | |
| } | |
| } | |
| } else { | |
| expectedLines = headerFormat.split("(?:\r)?\n|\r"); | |
| } | |
| } |
- Mark as noise
Modify S1451 to handle empty header separately whether or not it is marked as a regular expression.