From 5bbec23123f5b64b322d2d1f07c88943eac2dc4b Mon Sep 17 00:00:00 2001 From: Kirill Rakhman Date: Mon, 26 Feb 2024 18:09:49 +0100 Subject: [PATCH] [Test gen] Consolidate file reads for checking directives --- .../kotlin/test/InTextDirectivesUtils.java | 55 ++++++++++++++++--- .../generators/model/SimpleTestMethodModel.kt | 14 ++++- .../generators/util/MethodModelLocator.kt | 3 +- 3 files changed, 61 insertions(+), 11 deletions(-) diff --git a/compiler/test-infrastructure-utils/tests/org/jetbrains/kotlin/test/InTextDirectivesUtils.java b/compiler/test-infrastructure-utils/tests/org/jetbrains/kotlin/test/InTextDirectivesUtils.java index 567d0d4d32e..d7c884392e2 100644 --- a/compiler/test-infrastructure-utils/tests/org/jetbrains/kotlin/test/InTextDirectivesUtils.java +++ b/compiler/test-infrastructure-utils/tests/org/jetbrains/kotlin/test/InTextDirectivesUtils.java @@ -31,6 +31,9 @@ public final class InTextDirectivesUtils { public static final String[] IGNORE_BACKEND_DIRECTIVE_PREFIXES = { IGNORE_BACKEND_DIRECTIVE_PREFIX, IGNORE_BACKEND_K1_DIRECTIVE_PREFIX }; + public static final String TARGET_BACKEND_DIRECTIVE_PREFIX = "// TARGET_BACKEND: "; + public static final String DORT_TARGET_EXACT_BACKEND_DIRECTIVE_PREFIX = "// DONT_TARGET_EXACT_BACKEND: "; + private InTextDirectivesUtils() { } @@ -109,15 +112,20 @@ public final class InTextDirectivesUtils { @NotNull public static List findLinesWithPrefixesRemoved(@NotNull String fileText, @NotNull String... prefixes) { - return findLinesWithPrefixesRemoved(fileText, true, true, prefixes); + return findLinesByPrefixRemoved(fileText, true, true, prefixes).values().stream().flatMap(Collection::stream).collect(Collectors.toList()); } @NotNull - public static List findLinesWithPrefixesRemoved(@NotNull String fileText, boolean trim, boolean strict, @NotNull String... prefixes) { + public static Map> findLinesByPrefixRemoved(@NotNull String fileText, @NotNull String... prefixes) { + return findLinesByPrefixRemoved(fileText, true, true, prefixes); + } + + @NotNull + public static Map> findLinesByPrefixRemoved(@NotNull String fileText, boolean trim, boolean strict, @NotNull String... prefixes) { if (prefixes.length == 0) { throw new IllegalArgumentException("Please specify the prefixes to check"); } - List result = new ArrayList<>(); + Map> result = new HashMap<>(); List cleanedPrefixes = cleanDirectivesFromComments(Arrays.asList(prefixes)); for (String line : fileNonEmptyCommentedLines(fileText)) { @@ -128,7 +136,7 @@ public final class InTextDirectivesUtils { if (noPrefixLine.isEmpty() || Character.isWhitespace(noPrefixLine.charAt(0)) || Character.isWhitespace(prefix.charAt(prefix.length() - 1))) { - result.add(trim ? noPrefixLine.trim() : StringUtil.trimTrailing(StringsKt.drop(noPrefixLine, 1))); + result.computeIfAbsent(prefix, s -> new ArrayList<>()).add(trim ? noPrefixLine.trim() : StringUtil.trimTrailing(StringsKt.drop(noPrefixLine, 1))); break; } else if (strict) { throw new AssertionError( @@ -209,7 +217,7 @@ public final class InTextDirectivesUtils { return result; } - private static String textWithDirectives(@NotNull File file) { + public static String textWithDirectives(@NotNull File file) { try { String fileText; if (file.isDirectory()) { @@ -229,13 +237,21 @@ public final class InTextDirectivesUtils { public static boolean isCompatibleTarget(@NotNull TargetBackend targetBackend, @NotNull File file) { if (targetBackend == TargetBackend.ANY) return true; + String textWithDirectives = textWithDirectives(file); + Map> byPrefixRemoved = + findLinesByPrefixRemoved(textWithDirectives, DORT_TARGET_EXACT_BACKEND_DIRECTIVE_PREFIX, TARGET_BACKEND_DIRECTIVE_PREFIX); + return isCompatibleTarget(targetBackend, byPrefixRemoved); + } - List doNotTarget = findLinesWithPrefixesRemoved(textWithDirectives(file), "// DONT_TARGET_EXACT_BACKEND: "); + public static boolean isCompatibleTarget(@NotNull TargetBackend targetBackend, Map> directives) { + if (targetBackend == TargetBackend.ANY) return true; + + List doNotTarget = directives.getOrDefault("DONT_TARGET_EXACT_BACKEND: ", Collections.emptyList()); doNotTarget = doNotTarget.stream().flatMap((s) -> Arrays.stream(s.split(" "))).collect(Collectors.toList()); if (doNotTarget.contains(targetBackend.name())) return false; - List backends = findLinesWithPrefixesRemoved(textWithDirectives(file), "// TARGET_BACKEND: "); + List backends = directives.getOrDefault("TARGET_BACKEND: ", Collections.emptyList()); return isCompatibleTargetExceptAny(targetBackend, backends); } @@ -250,6 +266,31 @@ public final class InTextDirectivesUtils { public static boolean isIgnoredTarget(@NotNull TargetBackend targetBackend, @NotNull File file, boolean includeAny, String... ignoreBackendDirectivePrefixes) { List ignoredBackends = findListWithPrefixes(textWithDirectives(file), ignoreBackendDirectivePrefixes); + return isIgnoredTarget(targetBackend, includeAny, ignoredBackends); + } + + public static boolean isIgnoredTarget( + @NotNull TargetBackend targetBackend, + @NotNull Map> directives, + boolean includeAny, + String... ignoreBackendDirectivePrefixes + ) { + List result = new ArrayList<>(); + directives + .entrySet() + .stream() + .filter(entry -> entry.getKey().startsWith("IGNORE_BACKEND")) + .forEach(entry -> + { + for (String s : entry.getValue()) { + splitValues(result, s); + } + } + ); + return isIgnoredTarget(targetBackend, includeAny, result); + } + + private static boolean isIgnoredTarget(@NotNull TargetBackend targetBackend, boolean includeAny, List ignoredBackends) { if (ignoredBackends.contains(targetBackend.name())) return true; if (includeAny && ignoredBackends.contains("ANY")) return true; return false; diff --git a/generators/test-generator/tests/org/jetbrains/kotlin/generators/model/SimpleTestMethodModel.kt b/generators/test-generator/tests/org/jetbrains/kotlin/generators/model/SimpleTestMethodModel.kt index 1674a3c42f1..1a2f37fdd66 100644 --- a/generators/test-generator/tests/org/jetbrains/kotlin/generators/model/SimpleTestMethodModel.kt +++ b/generators/test-generator/tests/org/jetbrains/kotlin/generators/model/SimpleTestMethodModel.kt @@ -23,6 +23,16 @@ open class SimpleTestMethodModel( ) : MethodModel { object Kind : MethodModel.Kind() + val directives: Map> by lazy(LazyThreadSafetyMode.NONE) { + InTextDirectivesUtils.findLinesByPrefixRemoved( + InTextDirectivesUtils.textWithDirectives(file), + *InTextDirectivesUtils.IGNORE_BACKEND_DIRECTIVE_PREFIXES, + InTextDirectivesUtils.TARGET_BACKEND_DIRECTIVE_PREFIX, + InTextDirectivesUtils.DORT_TARGET_EXACT_BACKEND_DIRECTIVE_PREFIX, + "// WORKS_WHEN_VALUE_CLASS" + ) + } + override val kind: MethodModel.Kind get() = Kind @@ -33,7 +43,7 @@ open class SimpleTestMethodModel( } override fun shouldBeGenerated(): Boolean { - return InTextDirectivesUtils.isCompatibleTarget(targetBackend, file) + return InTextDirectivesUtils.isCompatibleTarget(targetBackend, directives) } override val name: String @@ -53,7 +63,7 @@ open class SimpleTestMethodModel( val relativePath = FileUtil.getRelativePath(rootDir, file.parentFile) relativePath + "-" + extractedName.replaceFirstChar(Char::uppercaseChar) } - val ignored = skipIgnored && InTextDirectivesUtils.isIgnoredTarget(targetBackend, file) + val ignored = skipIgnored && InTextDirectivesUtils.isIgnoredTarget(targetBackend, directives, false) return (if (ignored) "ignore" else "test") + escapeForJavaIdentifier(unescapedName).replaceFirstChar(Char::uppercaseChar) } diff --git a/generators/test-generator/tests/org/jetbrains/kotlin/generators/util/MethodModelLocator.kt b/generators/test-generator/tests/org/jetbrains/kotlin/generators/util/MethodModelLocator.kt index cf21c4aa7f3..e7e6dfc23e5 100644 --- a/generators/test-generator/tests/org/jetbrains/kotlin/generators/util/MethodModelLocator.kt +++ b/generators/test-generator/tests/org/jetbrains/kotlin/generators/util/MethodModelLocator.kt @@ -10,13 +10,12 @@ import org.jetbrains.kotlin.test.TargetBackend import java.io.File import java.util.regex.Pattern -const val WORKS_WHEN_VALUE_CLASS = "WORKS_WHEN_VALUE_CLASS" // will replace OPTIONAL_JVM_INLINE_ANNOTATION with @JvmInline or remove it depending on compiler backend // for JVM IR both ones are generated according to value classes feature (https://github.com/Kotlin/KEEP/issues/237) fun TestEntityModel.containsWithoutJvmInline(): Boolean = when (this) { is ClassModel -> methods.any { it.containsWithoutJvmInline() } || innerTestClasses.any { it.containsWithoutJvmInline() } - is SimpleTestMethodModel -> file.isFile && file.readLines().any { Regex("^\\s*//\\s*$WORKS_WHEN_VALUE_CLASS\\s*$").matches(it) } + is SimpleTestMethodModel -> file.isFile && "WORKS_WHEN_VALUE_CLASS" in directives else -> false }