in subprojects/groovy-typecheckers/src/main/groovy/groovy/typecheckers/RegexChecker.groovy [108:267]
Object run() {
beforeVisitMethod { MethodNode method ->
def visitor = new CheckingVisitor() {
@Override
void visitBitwiseNegationExpression(BitwiseNegationExpression expression) {
super.visitBitwiseNegationExpression(expression)
def exp = findConstExp(expression.expression, String)
checkRegex(exp, expression)
}
@Override
void visitBinaryExpression(BinaryExpression expression) {
super.visitBinaryExpression(expression)
if (expression.operation.type in [Types.FIND_REGEX, Types.MATCH_REGEX]) {
def exp = findConstExp(expression.rightExpression, String)
checkRegex(exp, expression)
} else if (expression.operation.type == Types.LEFT_SQUARE_BRACKET) {
if (isVariableExpression(expression.leftExpression)) {
def var = findTargetVariable(expression.leftExpression)
def groupCount = var?.getNodeMetaData(REGEX_GROUP_COUNT)
if (groupCount != null) {
expression.putNodeMetaData(REGEX_GROUP_COUNT, groupCount)
if (groupCount == 0) {
expression.putNodeMetaData(REGEX_MATCHER_RESULT_TYPE, STRING_TYPE)
} else {
expression.putNodeMetaData(REGEX_MATCHER_RESULT_TYPE, buildListType(STRING_TYPE.plainNodeReference))
}
}
}
}
}
@Override
void visitMethodCallExpression(MethodCallExpression call) {
super.visitMethodCallExpression(call)
if (isClassExpression(call.objectExpression)) {
checkPatternMethod(call, call.objectExpression.type)
} else if (isPattern(call.receiver) && call.methodAsString == 'matcher') {
def var = findTargetVariable(call.receiver)
def groupCount = var?.getNodeMetaData(REGEX_GROUP_COUNT)
if (groupCount != null) {
call.putNodeMetaData(REGEX_GROUP_COUNT, groupCount)
}
}
}
@Override
void visitStaticMethodCallExpression(StaticMethodCallExpression call) {
super.visitStaticMethodCallExpression(call)
checkPatternMethod(call, call.ownerType)
}
private void checkPatternMethod(MethodCall call, ClassNode classType) {
def arguments = call.arguments
if (classType == PATTERN_TYPE && call.methodAsString in ['compile', 'matches'] && arguments.expressions) {
def exp = findConstExp(arguments.getExpression(0), String)
checkRegex(exp, call)
}
}
@Override
void visitDeclarationExpression(DeclarationExpression decl) {
super.visitDeclarationExpression(decl)
if (decl.variableExpression != null) {
if (isConstantExpression(decl.rightExpression)) {
localConstVars.put(decl.variableExpression, decl.rightExpression)
}
def groupCount = decl.rightExpression.getNodeMetaData(REGEX_GROUP_COUNT)
if (groupCount != null) {
decl.variableExpression.putNodeMetaData(REGEX_GROUP_COUNT, groupCount)
}
}
}
}
method.code.visit(visitor)
}
incompatibleAssignment { lhsType, rhsType, expr ->
if (isBinaryExpression(expr) && isAssignment(expr.operation.type)) {
def from = expr.rightExpression
if (isBinaryExpression(from) && from.operation.type == Types.LEFT_SQUARE_BRACKET && getType(from.leftExpression) == MATCHER_TYPE) {
ClassNode inferred = from.getNodeMetaData(REGEX_MATCHER_RESULT_TYPE)
if (inferred) {
handled = true
if (checkCompatibleAssignmentTypes(lhsType, inferred, from)) {
storeType(expr, inferred)
} else {
addStaticTypeError('Cannot assign value of type ' + inferred + ' to variable of type ' + lhsType, expr)
}
}
}
}
}
methodNotFound { receiverType, name, argList, argTypes, call ->
def receiver = call.receiver
if (isBinaryExpression(receiver) && receiver.operation.type == Types.LEFT_SQUARE_BRACKET && getType(receiver.leftExpression) == MATCHER_TYPE) {
ClassNode inferred = receiver.getNodeMetaData(REGEX_MATCHER_RESULT_TYPE)
if (inferred) {
makeDynamic(call, inferred)
}
}
}
afterVisitMethod { MethodNode method ->
def visitor = new CheckingVisitor() {
@Override
void visitDeclarationExpression(DeclarationExpression decl) {
super.visitDeclarationExpression(decl)
if (decl.variableExpression != null) {
if (isConstantExpression(decl.rightExpression)) {
localConstVars.put(decl.variableExpression, decl.rightExpression)
}
def groupCount = decl.rightExpression.getNodeMetaData(REGEX_GROUP_COUNT)
if (groupCount != null) {
decl.variableExpression.putNodeMetaData(REGEX_GROUP_COUNT, groupCount)
}
}
}
@Override
void visitMethodCallExpression(MethodCallExpression call) {
if (isPattern(call.receiver) && call.methodAsString == 'matcher') {
def var = findTargetVariable(call.receiver)
def groupCount = var?.getNodeMetaData(REGEX_GROUP_COUNT)
if (groupCount != null) {
call.putNodeMetaData(REGEX_GROUP_COUNT, groupCount)
}
}
super.visitMethodCallExpression(call)
if (isVariableExpression(call.objectExpression) && call.methodAsString == 'group' && isMatcher(call.receiver) && call.arguments.expressions) {
def var = findTargetVariable(call.receiver)
def maxCnt = var?.getNodeMetaData(REGEX_GROUP_COUNT)
if (maxCnt != null) {
def cnt = findConstExp(call.arguments.getExpression(0), Integer).value
if (cnt > maxCnt) {
addStaticTypeError('Invalid group count ' + cnt + ' for regex with ' + maxCnt + ' group' + (maxCnt == 1 ? '' : 's'), call)
}
}
}
}
@Override
void visitBinaryExpression(BinaryExpression expression) {
super.visitBinaryExpression(expression)
if (expression.operation.type == Types.LEFT_SQUARE_BRACKET) {
def maxCnt = expression.leftExpression?.getNodeMetaData(REGEX_GROUP_COUNT)
if (maxCnt != null) {
def cnt = findConstExp(expression.rightExpression, Integer).value
if (cnt > maxCnt) {
addStaticTypeError('Invalid group count ' + cnt + ' for regex with ' + maxCnt + ' group' + (maxCnt == 1 ? '' : 's'), expression)
}
}
}
}
}
method.code.visit(visitor)
}
}