Skip to content

Commit

Permalink
Validator support for sealed interfaces (#123)
Browse files Browse the repository at this point in the history
  • Loading branch information
Squiry authored Apr 13, 2023
1 parent 523cd1e commit ddec85f
Show file tree
Hide file tree
Showing 18 changed files with 985 additions and 524 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,10 @@
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.*;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.IntStream;

@TestInstance(TestInstance.Lifecycle.PER_METHOD)
public abstract class AbstractAnnotationProcessorTest {
Expand Down Expand Up @@ -77,37 +76,25 @@ protected CompileResult compile(List<Processor> processors, @Language("java") St
var commonImports = this.commonImports();
var sourceList = Arrays.stream(sources).map(s -> "package %s;\n%s\n/**\n* @see %s#%s \n*/\n".formatted(testPackage, commonImports, testClass.getCanonicalName(), testMethod.getName()) + s)
.map(s -> {
var classStart = s.indexOf("public sealed interface ") + 24;
if (classStart < 24) {
classStart = s.indexOf("public class ") + 13;
if (classStart < 13) {
classStart = s.indexOf("public final class ") + 19;
if (classStart < 19) {
classStart = s.indexOf("public interface ") + 17;
if (classStart < 17) {
classStart = s.indexOf("public @interface ") + 18;
if (classStart < 18) {
classStart = s.indexOf("public record ") + 14;
if (classStart < 14) {
classStart = s.indexOf("public enum ") + 12;
if (classStart < 12) {
throw new IllegalArgumentException();
}
}
}
}
}
}
}
var firstSpace = s.indexOf(" ", classStart + 1);
var firstBracket = s.indexOf("(", classStart + 1);
var firstSquareBracket = s.indexOf("{", classStart + 1);
var classEnd = Math.min(firstSpace >= 0 ? firstSpace : Integer.MAX_VALUE, Math.min(
firstBracket >= 0 ? firstBracket : Integer.MAX_VALUE,
firstSquareBracket >= 0 ? firstSquareBracket : Integer.MAX_VALUE
));
var className = s.substring(classStart, classEnd);
return new ByteArrayJavaFileObject(JavaFileObject.Kind.SOURCE, testPackage + "." + className, s.getBytes(StandardCharsets.UTF_8));
var prefixes = List.of("class ", "interface ", "@interface ", "record ", "enum ");
var firstClass = prefixes.stream()
.map(p -> Map.entry(s.indexOf(p), p.length()))
.filter(e -> e.getKey() >= 0)
.map(e -> e.getKey() + e.getValue())
.min(Comparator.comparing(Function.identity()))
.map(classStart -> {
var firstSpace = s.indexOf(" ", classStart + 1);
var firstBracket = s.indexOf("(", classStart + 1);
var firstSquareBracket = s.indexOf("{", classStart + 1);
var classEnd = IntStream.of(firstSpace, firstBracket, firstSquareBracket)
.filter(i -> i >= 0)
.min()
.getAsInt();
return s.substring(classStart, classEnd).trim();
})
.get();

return new ByteArrayJavaFileObject(JavaFileObject.Kind.SOURCE, testPackage + "." + firstClass, s.getBytes(StandardCharsets.UTF_8));
})
.toList();
try (var delegate = javaCompiler.getStandardFileManager(diagnostic::add, Locale.US, StandardCharsets.UTF_8);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,10 @@ fun KSAnnotated.getOuterClassesAsPrefix(): String {
return prefix.toString()
}

fun KSDeclaration.generatedClass(suffix: String): String {
return this.getOuterClassesAsPrefix() + this.simpleName.asString() + "_" + suffix
}

fun KSClassDeclaration.generatedClassName(postfix: String): String {
val prefix = StringBuilder("$")
var parent = this.parent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,32 +73,23 @@ abstract class AbstractSymbolProcessorTest {
val sourceList: List<SourceFile> =
Arrays.stream(sources).map { s: String -> "package %s;\n%s\n/**\n* @see %s.%s \n*/\n".formatted(testPackage, commonImports, testClass.canonicalName, testMethod.name) + s }
.map { s ->
var classStart = s.indexOf("\nclass ") + 7
if (classStart < 7) {
classStart = s.indexOf("\nopen class ") + 12
if (classStart < 12) {
classStart = s.indexOf("\ninterface ") + 11
if (classStart < 11) {
classStart = s.indexOf("\nsealed interface ") + 18
if (classStart < 18) {
classStart = s.indexOf("data class ") + 11
if (classStart < 11) {
classStart = s.indexOf("enum class ") + 11
require(classStart >= 12)
}
}
}
val firstClass = s.indexOf("class ") to "class ".length
val firstInterface = s.indexOf("interface ") to "interface ".length
val classNameLocation = sequenceOf(firstClass, firstInterface)
.filter { it.first >= 0 }
.map { it.first + it.second }
.flatMap {
sequenceOf(
s.indexOf(" ", it + 1),
s.indexOf("(", it + 1),
s.indexOf("{", it + 1),
s.indexOf(":", it + 1),
)
.map { it1 -> it to it1 }
}
}
val classEnd = sequenceOf(
s.indexOf(" ", classStart + 1),
s.indexOf("(", classStart + 1),
s.indexOf("{", classStart + 1),
s.indexOf(":", classStart + 1),
)
.filter { it >= 0 }
.min()
val className = s.substring(classStart, classEnd)
.filter { it.second >= 0 }
.minBy { it.second }
val className = s.substring(classNameLocation.first - 1, classNameLocation.second)
val fileName = "build/in-test-generated-ksp/sources/${testPackage.replace('.', '/')}/$className.kt"
Files.createDirectories(File(fileName).toPath().parent)
Files.deleteIfExists(Paths.get(fileName))
Expand Down Expand Up @@ -142,6 +133,12 @@ abstract class AbstractSymbolProcessorTest {
throw RuntimeException(errorMessages.joinToString("\n"))
}

fun assertSuccess() {
if (isFailed()) {
throw compilationException()
}
}

}

protected fun symbolProcessFiles(srcFiles: List<SourceFile>, annotationProcessorProviders: List<SymbolProcessorProvider>): CompileResult {
Expand Down
Loading

0 comments on commit ddec85f

Please sign in to comment.