Object run()

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)
        }
    }