All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openrewrite.groovy.GroovyParser Maven / Gradle / Ivy

There is a newer version: 8.40.2
Show newest version
/*
 * Copyright 2021 the original author or authors.
 * 

* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at *

* https://www.apache.org/licenses/LICENSE-2.0 *

* Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.openrewrite.groovy; import groovy.lang.GroovyClassLoader; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; import org.codehaus.groovy.ast.ClassNode; import org.codehaus.groovy.ast.ModuleNode; import org.codehaus.groovy.control.*; import org.codehaus.groovy.control.io.InputStreamReaderSource; import org.codehaus.groovy.control.messages.WarningMessage; import org.codehaus.groovy.transform.stc.StaticTypeCheckingVisitor; import org.intellij.lang.annotations.Language; import org.jspecify.annotations.Nullable; import org.openrewrite.*; import org.openrewrite.groovy.tree.G; import org.openrewrite.java.JavaParser; import org.openrewrite.java.internal.JavaTypeCache; import org.openrewrite.marker.Markers; import org.openrewrite.style.NamedStyles; import org.openrewrite.tree.ParseError; import org.openrewrite.tree.ParsingExecutionContextView; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.nio.file.Paths; import java.util.*; import java.util.function.Consumer; import java.util.function.Function; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Stream; import java.util.stream.StreamSupport; import static java.util.Collections.emptyList; import static java.util.stream.Collectors.toList; @RequiredArgsConstructor(access = AccessLevel.PRIVATE) public class GroovyParser implements Parser { @Nullable private final Collection classpath; private final List styles; private final boolean logCompilationWarningsAndErrors; private final JavaTypeCache typeCache; private final List> compilerCustomizers; @Override public Stream parse(@Language("groovy") String... sources) { Pattern packagePattern = Pattern.compile("^package\\s+([^;]+);"); Pattern classPattern = Pattern.compile("(class|interface|enum)\\s*(<[^>]*>)?\\s+(\\w+)"); Function simpleName = sourceStr -> { Matcher classMatcher = classPattern.matcher(sourceStr); return classMatcher.find() ? classMatcher.group(3) : null; }; return parseInputs( Arrays.stream(sources) .map(sourceFile -> { Matcher packageMatcher = packagePattern.matcher(sourceFile); String pkg = packageMatcher.find() ? packageMatcher.group(1).replace('.', '/') + "/" : ""; String className = Optional.ofNullable(simpleName.apply(sourceFile)) .orElse(Long.toString(System.nanoTime())) + ".java"; Path path = Paths.get(pkg + className); return new Input( path, null, () -> new ByteArrayInputStream(sourceFile.getBytes(StandardCharsets.UTF_8)), true ); }) .collect(toList()), null, new InMemoryExecutionContext() ); } @Override public Stream parseInputs(Iterable sources, @Nullable Path relativeTo, ExecutionContext ctx) { CompilerConfiguration configuration = new CompilerConfiguration(); configuration.setTolerance(Integer.MAX_VALUE); configuration.setWarningLevel(WarningMessage.NONE); configuration.setClasspathList(classpath == null ? emptyList() : classpath.stream() .flatMap(cp -> { try { return Stream.of(cp.toFile().toString()); } catch (UnsupportedOperationException e) { // can happen e.g. in the case of jdk.internal.jrtfs.JrtPath return Stream.empty(); } }) .collect(toList())); for (Consumer compilerCustomizer : compilerCustomizers) { compilerCustomizer.accept(configuration); } ParsingExecutionContextView pctx = ParsingExecutionContextView.view(ctx); return StreamSupport.stream(sources.spliterator(), false) .map(input -> { ParseWarningCollector errorCollector = new ParseWarningCollector(configuration, this); try (GroovyClassLoader classLoader = new GroovyClassLoader(getClass().getClassLoader(), configuration, true)) { SourceUnit unit = new SourceUnit( "doesntmatter", new InputStreamReaderSource(input.getSource(ctx), configuration), configuration, classLoader, errorCollector ); pctx.getParsingListener().startedParsing(input); CompilationUnit compUnit = new CompilationUnit(configuration, null, classLoader, classLoader); compUnit.addSource(unit); compUnit.compile(Phases.CANONICALIZATION); ModuleNode ast = unit.getAST(); for (ClassNode aClass : ast.getClasses()) { try { StaticTypeCheckingVisitor staticTypeCheckingVisitor = new StaticTypeCheckingVisitor(unit, aClass); staticTypeCheckingVisitor.setCompilationUnit(compUnit); staticTypeCheckingVisitor.visitClass(aClass); } catch (NoClassDefFoundError ignored) { } } CompiledGroovySource compiled = new CompiledGroovySource(input, unit, ast); List warnings = errorCollector.getWarningMarkers(); GroovyParserVisitor mappingVisitor = new GroovyParserVisitor( compiled.getInput().getRelativePath(relativeTo), compiled.getInput().getFileAttributes(), compiled.getInput().getSource(ctx), typeCache, ctx ); G.CompilationUnit gcu = mappingVisitor.visit(compiled.getSourceUnit(), compiled.getModule()); if (warnings.size() > 0) { Markers m = gcu.getMarkers(); for (ParseWarning warning : warnings) { m = m.add(warning); } gcu = gcu.withMarkers(m); } pctx.getParsingListener().parsed(compiled.getInput(), gcu); return requirePrintEqualsInput(gcu, input, relativeTo, ctx); } catch (Throwable t) { ctx.getOnError().accept(t); return ParseError.build(this, input, relativeTo, ctx, t); } finally { if (logCompilationWarningsAndErrors && (errorCollector.hasErrors() || errorCollector.hasWarnings())) { try (StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw)) { errorCollector.write(pw, new Janitor()); org.slf4j.LoggerFactory.getLogger(GroovyParser.class).warn(sw.toString()); } catch (IOException ignored) { // unreachable } } } }); } @Override public boolean accept(Path path) { return path.toString().endsWith(".groovy") || path.toFile().getName().startsWith("Jenkinsfile"); } @Override public GroovyParser reset() { typeCache.clear(); return this; } @Override public Path sourcePathFromSourceText(Path prefix, String sourceCode) { return prefix.resolve("file.groovy"); } public static GroovyParser.Builder builder() { return new Builder(); } public static GroovyParser.Builder builder(Builder base) { return new Builder(base); } @SuppressWarnings("unused") public static class Builder extends Parser.Builder { @Nullable private Collection classpath = Collections.emptyList(); @Nullable protected Collection artifactNames = Collections.emptyList(); private JavaTypeCache typeCache = new JavaTypeCache(); private boolean logCompilationWarningsAndErrors = false; private final List styles = new ArrayList<>(); private final List> compilerCustomizers = new ArrayList<>(); public Builder() { super(G.CompilationUnit.class); } public Builder(Builder base) { super(G.CompilationUnit.class); this.classpath = base.classpath; this.artifactNames = base.artifactNames; this.typeCache = base.typeCache; this.logCompilationWarningsAndErrors = base.logCompilationWarningsAndErrors; this.styles.addAll(base.styles); this.compilerCustomizers.addAll(base.compilerCustomizers); } public Builder logCompilationWarningsAndErrors(boolean logCompilationWarningsAndErrors) { this.logCompilationWarningsAndErrors = logCompilationWarningsAndErrors; return this; } public Builder classpath(@Nullable Collection classpath) { this.artifactNames = null; this.classpath = classpath; return this; } public Builder classpath(@Nullable String... artifactNames) { this.artifactNames = Arrays.asList(artifactNames); this.classpath = null; return this; } public Builder classpathFromResource(ExecutionContext ctx, String... artifactNamesWithVersions) { this.artifactNames = null; this.classpath = JavaParser.dependenciesFromResources(ctx, artifactNamesWithVersions); return this; } @SuppressWarnings("unused") public Builder typeCache(JavaTypeCache typeCache) { this.typeCache = typeCache; return this; } public Builder styles(Iterable styles) { for (NamedStyles style : styles) { this.styles.add(style); } return this; } @SafeVarargs public final GroovyParser.Builder compilerCustomizers(Consumer... compilerCustomizers) { return compilerCustomizers(Arrays.asList(compilerCustomizers)); } public GroovyParser.Builder compilerCustomizers(Iterable> compilerCustomizers) { for (Consumer compilerCustomizer : compilerCustomizers) { this.compilerCustomizers.add(compilerCustomizer); } return this; } private @Nullable Collection resolvedClasspath() { if (artifactNames != null && !artifactNames.isEmpty()) { classpath = JavaParser.dependenciesFromClasspath(artifactNames.toArray(new String[0])); artifactNames = null; } return classpath; } @Override public GroovyParser build() { return new GroovyParser(resolvedClasspath(), styles, logCompilationWarningsAndErrors, typeCache, compilerCustomizers); } @Override public String getDslName() { return "groovy"; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy