checker.src.org.checkerframework.checker.experimental.regex_qual.RegexTypecheckVisitor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of checker Show documentation
Show all versions of checker Show documentation
The Checker Framework enhances Java’s type system to
make it more powerful and useful. This lets software developers
detect and prevent errors in their Java programs.
The Checker Framework includes compiler plug-ins ("checkers")
that find bugs or verify their absence. It also permits you to
write your own compiler plug-ins.
package org.checkerframework.checker.experimental.regex_qual;
import org.checkerframework.framework.source.Result;
import org.checkerframework.javacutil.TreeUtils;
import org.checkerframework.qualframework.base.CheckerAdapter;
import org.checkerframework.qualframework.base.QualifiedTypeMirror;
import org.checkerframework.qualframework.base.TypecheckVisitorAdapter;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.VariableElement;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.LiteralTree;
import com.sun.source.tree.MemberSelectTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.Tree;
/**
* The {@link org.checkerframework.common.basetype.BaseTypeVisitor} for the Regex-Qual type system.
*/
public class RegexTypecheckVisitor extends TypecheckVisitorAdapter {
private final ExecutableElement matchResultEnd;
private final ExecutableElement matchResultGroup;
private final ExecutableElement matchResultStart;
private final ExecutableElement patternCompile;
private final VariableElement patternLiteral;
public RegexTypecheckVisitor(CheckerAdapter checker) {
super(checker);
ProcessingEnvironment env = checker.getProcessingEnvironment();
this.matchResultEnd = TreeUtils.getMethod("java.util.regex.MatchResult", "end", 1, env);
this.matchResultGroup = TreeUtils.getMethod("java.util.regex.MatchResult", "group", 1, env);
this.matchResultStart = TreeUtils.getMethod("java.util.regex.MatchResult", "start", 1, env);
this.patternCompile = TreeUtils.getMethod("java.util.regex.Pattern", "compile", 2, env);
this.patternLiteral = TreeUtils.getField("java.util.regex.Pattern", "LITERAL", env);
}
@Override
public Void visitMethodInvocation(MethodInvocationTree node, Void p) {
/**
* Case 1: Don't require a Regex.RegexVal qualifier on the String argument to
* Pattern.compile if the Pattern.LITERAL flag is passed.
*/
ProcessingEnvironment env = checker.getProcessingEnvironment();
if (TreeUtils.isMethodInvocation(node, patternCompile, env)) {
ExpressionTree flagParam = node.getArguments().get(1);
if (flagParam.getKind() == Tree.Kind.MEMBER_SELECT) {
MemberSelectTree memSelect = (MemberSelectTree) flagParam;
if (TreeUtils.isSpecificFieldAccess(memSelect, patternLiteral)) {
// This is a call to Pattern.compile with the Pattern.LITERAL
// flag so the first parameter doesn't need to be a
// @Regex String. Don't call the super method to skip checking
// if the first parameter is a @Regex String, but make sure to
// still recurse on all of the different parts of the method call.
Void r = scan(node.getTypeArguments(), p);
r = reduce(scan(node.getMethodSelect(), p), r);
r = reduce(scan(node.getArguments(), p), r);
return r;
}
}
} else if (TreeUtils.isMethodInvocation(node, matchResultEnd, env)
|| TreeUtils.isMethodInvocation(node, matchResultGroup, env)
|| TreeUtils.isMethodInvocation(node, matchResultStart, env)) {
/**
* Case 3: Checks calls to {@code MatchResult.start}, {@code MatchResult.end}
* and {@code MatchResult.group} to ensure that a valid group number is passed.
*/
ExpressionTree group = node.getArguments().get(0);
if (group.getKind() == Tree.Kind.INT_LITERAL) {
LiteralTree literal = (LiteralTree) group;
int paramGroups = (Integer) literal.getValue();
ExpressionTree receiver = TreeUtils.getReceiverTree(node);
int annoGroups = 0;
QualifiedTypeMirror receiverType = context.getTypeFactory().getQualifiedType(receiver);
Regex regex = receiverType.getQualifier();
if (!regex.isRegexVal() || ((Regex.RegexVal) regex).getCount() < paramGroups) {
checker.report(Result.failure("group.count.invalid", paramGroups, annoGroups, receiver), group);
}
} else {
checker.report(Result.warning("group.count.unknown"), group);
}
}
return super.visitMethodInvocation(node, p);
}
}