Let's get a bit more specific. How many places does the year of my birthdate exist in a literal somewhere in the codebase. Comments don't count. Variable names don't count.
Can you imagine doing something like this with a regular expression?
// 12-05-1983
class Hey {
void itsYourBirthday() {
int year = 1983; // match!
}
/* An oddly specific method about 1983 */
int importantThingsThatHappenedIn1983() {
return 0;
}
}
Opportunity for an OpenRewrite recipe! OpenRewrite operates on a Lossless Semantic Tree (LST), which is kind of like a super super enriched Abstract Syntax Tree (AST). Recipes use the visitor pattern at the most fundamental level to intercept certain types of syntax and check (and possibly transform!) them.
@Value
@EqualsAndHashCode(callSuper = false)
public class FindLiterals extends Recipe {
@Option(displayName = "Pattern",
description = "A regular expression pattern to match literals against.",
example = "file://")
String pattern;
@Override
public String getDisplayName() {
return "Find literals";
}
@Override
public String getDescription() {
return "Find literals matching a pattern.";
}
@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
Pattern compiledPattern = Pattern.compile(pattern);
return new JavaIsoVisitor<ExecutionContext>() {
@Override
public J.Literal visitLiteral(J.Literal literal, ExecutionContext ctx) {
if (literal.getValueSource() != null) {
if (literal.getType() == JavaType.Primitive.String) {
if (!literal.getValueSource().isEmpty() && compiledPattern.matcher(literal.getValueSource().substring(1, literal.getValueSource().length() - 1)).matches()) {
return SearchResult.found(literal);
}
}
if (compiledPattern.matcher(literal.getValueSource()).matches()) {
return SearchResult.found(literal);
}
}
return literal;
}
};
}
}
Can you spot the potential security vulnerability inherent in this recipe? Jonathan Leitschuh can. Even better, can you write a recipe that fixes this and every other similar vulnerability?