Martin Häusler created GROOVY-11563:
---------------------------------------

             Summary: CompileStatic does not detect type mismatch on "+="
                 Key: GROOVY-11563
                 URL: https://issues.apache.org/jira/browse/GROOVY-11563
             Project: Groovy
          Issue Type: Bug
          Components: Static compilation, Static Type Checker
    Affects Versions: 4.0.25
            Reporter: Martin Häusler


Hello,

I'm using Groovy 4.0.25 on OpenJDK 21. I'm using static compilation. It seems 
like the static typechecker is unable to find type issues related to the "+=" 
operator. I have a full self-contained JUnit test for you below.

In the test class, there are two test methods that check the output of the type 
checker.

Please note that "<number> += <string>" compiles without problems (and it 
really should report an issue here), but "<number> = <number> + <string>" 
produces the expected compilation issue.

 
{code:java}
import groovy.lang.GroovyClassLoader;
import groovy.transform.CompileStatic;
import org.codehaus.groovy.control.CompilationFailedException;
import org.codehaus.groovy.control.CompilationUnit;
import org.codehaus.groovy.control.CompilerConfiguration;
import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer;
import org.codehaus.groovy.control.messages.Message;
import org.codehaus.groovy.control.messages.WarningMessage;
import org.junit.jupiter.api.Test;

import java.util.List;
import java.util.UUID;

import static org.junit.jupiter.api.Assertions.fail;

public class GroovyCompilerStandaloneExampleTest {

    @Test
    public void testWithPlusEquals() throws Exception {
        try {
            compileGroovy(
                "Number x = 0\n" +
                    "x += \"hello\""
            );
            fail("No compile error!");
        } catch (CompilationFailedException e) {
            // success!
        }
    }

    @Test
    public void testWithAssignment() throws Exception {
        try {
            compileGroovy(
                "Number x = 0\n" +
                    "x = x + \"hello\""
            );
            fail("No compile error!");
        } catch (CompilationFailedException e) {
            // success!
        }
    }

    private Class<?> compileGroovy(String source) throws Exception {
        ClassLoader classLoader = 
Thread.currentThread().getContextClassLoader();
        CompilerConfiguration compilerConfig = createCompilerConfig();
        try (GroovyClassLoader gcl = new GroovyClassLoader(classLoader, 
compilerConfig)) {
            List<? extends Class<?>> classes = compileInternal(compilerConfig, 
gcl, source);
            return classes.getFirst();
        }
    }

    private CompilerConfiguration createCompilerConfig() {
        CompilerConfiguration config = new CompilerConfiguration();
        config.setWarningLevel(WarningMessage.PARANOIA);
        config.addCompilationCustomizers(
            new ASTTransformationCustomizer(CompileStatic.class)
        );
        return config;
    }

    private List<? extends Class<?>> compileInternal(
        CompilerConfiguration config,
        GroovyClassLoader gcl,
        String sourceCode
    ) throws Exception {
        CompilationUnit compilationUnit = new CompilationUnit(config, null, 
gcl);
        compilationUnit.addSource("script-" + UUID.randomUUID().toString(), 
sourceCode);
        compilationUnit.compile();
        List<? extends Message> errors = 
compilationUnit.getErrorCollector().getErrors();
        if (errors != null && !errors.isEmpty()) {
            fail("Groovy compilation has failed with " + errors.size() + " 
errors:\n" +
                String.join("\n - ", errors.toString()));
        }

        return compilationUnit.getClasses().stream().map(groovyClass -> {
            gcl.defineClass(groovyClass.getName(), groovyClass.getBytes());
            try {
                return gcl.loadClass(groovyClass.getName());
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
        }).toList();
    }
} {code}



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to