Effects: add test on (de)serialization of contracts

- Add ContractDescriptorRenderer
- Add option to dump function contracts in DescriptorRendererOptions
- Add parsing of LANGUAGE_VERSION directive in AbstractLoadJava
- Add tests on serialization-deserializaton identity of contracts

==========
Introduction of EffectSystem: 13/18
This commit is contained in:
Dmitry Savvinov
2017-10-03 15:02:46 +03:00
parent 75ad20f823
commit d20c770a25
29 changed files with 699 additions and 19 deletions
@@ -26,9 +26,7 @@ import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles;
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment;
import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM;
import org.jetbrains.kotlin.cli.jvm.config.JvmContentRootsKt;
import org.jetbrains.kotlin.config.CompilerConfiguration;
import org.jetbrains.kotlin.config.ContentRootsKt;
import org.jetbrains.kotlin.config.JVMConfigurationKeys;
import org.jetbrains.kotlin.config.*;
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
import org.jetbrains.kotlin.descriptors.ModuleDescriptor;
@@ -120,6 +118,8 @@ public abstract class AbstractLoadJavaTest extends TestCaseWithTmpdir {
if (useTypeTableInSerializer) {
configuration.put(JVMConfigurationKeys.USE_TYPE_TABLE, true);
}
updateConfigurationWithLanguageVersionDirective(ktFile, configuration);
KotlinCoreEnvironment environment =
KotlinCoreEnvironment.createForTests(getTestRootDisposable(), configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES);
registerJavacIfNeeded(environment);
@@ -129,7 +129,8 @@ public abstract class AbstractLoadJavaTest extends TestCaseWithTmpdir {
Assert.assertEquals("test", packageFromSource.getName().asString());
PackageViewDescriptor packageFromBinary = LoadDescriptorUtil.loadTestPackageAndBindingContextFromJavaRoot(
tmpdir, getTestRootDisposable(), getJdkKind(), configurationKind, true, false, useJavacWrapper()
tmpdir, getTestRootDisposable(), getJdkKind(), configurationKind, true, false, useJavacWrapper(),
configuration.get(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS)
).first;
for (DeclarationDescriptor descriptor : DescriptorUtils.getAllDescriptors(packageFromBinary.getMemberScope())) {
@@ -140,10 +141,21 @@ public abstract class AbstractLoadJavaTest extends TestCaseWithTmpdir {
DescriptorValidator.validate(errorTypesForbidden(), packageFromSource);
DescriptorValidator.validate(new DeserializedScopeValidationVisitor(), packageFromBinary);
Configuration comparatorConfiguration = COMPARATOR_CONFIGURATION.checkPrimaryConstructors(true).checkPropertyAccessors(true);
Configuration comparatorConfiguration = COMPARATOR_CONFIGURATION.checkPrimaryConstructors(true).checkPropertyAccessors(true).checkFunctionContracts(true);
compareDescriptors(packageFromSource, packageFromBinary, comparatorConfiguration, txtFile);
}
private static void updateConfigurationWithLanguageVersionDirective(File file, CompilerConfiguration configuration) throws IOException {
String version = InTextDirectivesUtils.findStringWithPrefixes(FileUtil.loadFile(file, true), "// LANGUAGE_VERSION:");
if (version != null) {
LanguageVersion explicitVersion = LanguageVersion.fromVersionString(version);
CommonConfigurationKeysKt.setLanguageVersionSettings(
configuration,
new LanguageVersionSettingsImpl(explicitVersion, ApiVersion.createByLanguageVersion(explicitVersion))
);
}
}
protected boolean useFastClassFilesReading() {
return false;
}
@@ -222,7 +234,7 @@ public abstract class AbstractLoadJavaTest extends TestCaseWithTmpdir {
Pair<PackageViewDescriptor, BindingContext> javaPackageAndContext = loadTestPackageAndBindingContextFromJavaRoot(
tmpdir, getTestRootDisposable(), getJdkKind(), ConfigurationKind.JDK_ONLY, false,
false, useJavacWrapper());
false, useJavacWrapper(), null);
checkJavaPackage(
expectedFile, javaPackageAndContext.first, javaPackageAndContext.second,
@@ -267,7 +279,7 @@ public abstract class AbstractLoadJavaTest extends TestCaseWithTmpdir {
) throws IOException {
compileJavaWithAnnotationsJar(javaFiles, outDir);
return loadTestPackageAndBindingContextFromJavaRoot(outDir, myTestRootDisposable, getJdkKind(), configurationKind, true,
useFastClassFilesReading(), useJavacWrapper());
useFastClassFilesReading(), useJavacWrapper(), null);
}
private static void checkJavaPackage(
@@ -25,6 +25,7 @@ import kotlin.io.FilesKt;
import kotlin.sequences.SequencesKt;
import kotlin.text.Charsets;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.analyzer.AnalysisResult;
import org.jetbrains.kotlin.cli.common.output.outputUtils.OutputUtilsKt;
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles;
@@ -32,8 +33,10 @@ import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment;
import org.jetbrains.kotlin.codegen.GenerationUtils;
import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime;
import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.config.CommonConfigurationKeys;
import org.jetbrains.kotlin.config.CompilerConfiguration;
import org.jetbrains.kotlin.config.JVMConfigurationKeys;
import org.jetbrains.kotlin.config.LanguageVersionSettings;
import org.jetbrains.kotlin.descriptors.ModuleDescriptor;
import org.jetbrains.kotlin.descriptors.PackageViewDescriptor;
import org.jetbrains.kotlin.jvm.compiler.javac.JavacRegistrarForTests;
@@ -80,7 +83,8 @@ public class LoadDescriptorUtil {
@NotNull ConfigurationKind configurationKind,
boolean isBinaryRoot,
boolean useFastClassReading,
boolean useJavacWrapper
boolean useJavacWrapper,
@Nullable LanguageVersionSettings explicitLanguageVersionSettings
) {
List<File> javaBinaryRoots = new ArrayList<>();
javaBinaryRoots.add(KotlinTestUtils.getAnnotationsJar());
@@ -97,6 +101,9 @@ public class LoadDescriptorUtil {
KotlinTestUtils.newConfiguration(configurationKind, testJdkKind, javaBinaryRoots, javaSourceRoots);
configuration.put(JVMConfigurationKeys.USE_FAST_CLASS_FILES_READING, useFastClassReading);
configuration.put(JVMConfigurationKeys.USE_JAVAC, useJavacWrapper);
if (explicitLanguageVersionSettings != null) {
configuration.put(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS, explicitLanguageVersionSettings);
}
KotlinCoreEnvironment environment =
KotlinCoreEnvironment.createForTests(disposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES);
if (useJavacWrapper) {
@@ -97,6 +97,7 @@ abstract class AbstractJvmRuntimeDescriptorLoaderTest : TestCaseWithTmpdir() {
/* checkPropertyAccessors = */ true,
/* includeMethodsOfKotlinAny = */ false,
/* renderDeclarationsFromOtherModules = */ true,
/* checkFunctionContract = */ false,
// Skip Java annotation constructors because order of their parameters is not retained at runtime
{ descriptor -> !descriptor!!.isJavaAnnotationConstructor() },
errorTypesForbidden(), renderer
@@ -109,7 +110,7 @@ abstract class AbstractJvmRuntimeDescriptorLoaderTest : TestCaseWithTmpdir() {
}
val expected = LoadDescriptorUtil.loadTestPackageAndBindingContextFromJavaRoot(
tmpdir, testRootDisposable, jdkKind, ConfigurationKind.ALL, true, false, false
tmpdir, testRootDisposable, jdkKind, ConfigurationKind.ALL, true, false, false, null
).first
RecursiveDescriptorComparator.validateAndCompareDescriptors(expected, actual, comparatorConfiguration, null)
@@ -22,6 +22,7 @@ import kotlin.Unit;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.contracts.description.*;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.impl.SubpackagesScope;
import org.jetbrains.kotlin.jvm.compiler.ExpectedLoadErrorsUtil;
@@ -63,12 +64,12 @@ public class RecursiveDescriptorComparator {
);
public static final Configuration DONT_INCLUDE_METHODS_OF_OBJECT = new Configuration(false, false, false, false,
descriptor -> true, errorTypesForbidden(), DEFAULT_RENDERER);
false, descriptor -> true, errorTypesForbidden(), DEFAULT_RENDERER);
public static final Configuration RECURSIVE = new Configuration(false, false, true, false,
descriptor -> true, errorTypesForbidden(), DEFAULT_RENDERER);
false, descriptor -> true, errorTypesForbidden(), DEFAULT_RENDERER);
public static final Configuration RECURSIVE_ALL = new Configuration(true, true, true, false,
descriptor -> true, errorTypesForbidden(), DEFAULT_RENDERER);
true, descriptor -> true, errorTypesForbidden(), DEFAULT_RENDERER);
public static final Predicate<DeclarationDescriptor> SKIP_BUILT_INS_PACKAGES = descriptor -> {
if (descriptor instanceof PackageViewDescriptor) {
@@ -111,6 +112,11 @@ public class RecursiveDescriptorComparator {
boolean isPrimaryConstructor = descriptor instanceof ConstructorDescriptor && ((ConstructorDescriptor) descriptor).isPrimary();
printer.print(isPrimaryConstructor && conf.checkPrimaryConstructors ? "/*primary*/ " : "", conf.renderer.render(descriptor));
if (descriptor instanceof FunctionDescriptor && conf.checkFunctionContracts) {
FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor;
printEffectsIfAny(functionDescriptor, printer);
}
if (isClassOrPackage) {
if (!topLevel) {
printer.printlnWithNoIndent(" {").pushIndent();
@@ -171,6 +177,24 @@ public class RecursiveDescriptorComparator {
}
}
private void printEffectsIfAny(FunctionDescriptor functionDescriptor, Printer printer) {
LazyContractProvider contractProvider = functionDescriptor.getUserData(ContractProviderKey.INSTANCE);
if (contractProvider == null) return;
ContractDescription contractDescription = contractProvider.getContractDescription();
if (contractDescription == null || contractDescription.getEffects().isEmpty()) return;
printer.println();
printer.pushIndent();
for (EffectDeclaration effect : contractDescription.getEffects()) {
StringBuilder sb = new StringBuilder();
ContractDescriptionRenderer renderer = new ContractDescriptionRenderer(sb);
effect.accept(renderer, Unit.INSTANCE);
printer.println(sb.toString());
}
printer.popIndent();
}
@NotNull
private MemberScope getPackageScopeInModule(@NotNull PackageViewDescriptor descriptor, @NotNull ModuleDescriptor module) {
// See LazyPackageViewDescriptorImpl#memberScope
@@ -298,6 +322,7 @@ public class RecursiveDescriptorComparator {
private final boolean checkPropertyAccessors;
private final boolean includeMethodsOfKotlinAny;
private final boolean renderDeclarationsFromOtherModules;
private final boolean checkFunctionContracts;
private final Predicate<DeclarationDescriptor> recursiveFilter;
private final DescriptorRenderer renderer;
private final DescriptorValidator.ValidationVisitor validationStrategy;
@@ -307,6 +332,7 @@ public class RecursiveDescriptorComparator {
boolean checkPropertyAccessors,
boolean includeMethodsOfKotlinAny,
boolean renderDeclarationsFromOtherModules,
boolean checkFunctionContracts,
Predicate<DeclarationDescriptor> recursiveFilter,
DescriptorValidator.ValidationVisitor validationStrategy,
DescriptorRenderer renderer
@@ -315,6 +341,7 @@ public class RecursiveDescriptorComparator {
this.checkPropertyAccessors = checkPropertyAccessors;
this.includeMethodsOfKotlinAny = includeMethodsOfKotlinAny;
this.renderDeclarationsFromOtherModules = renderDeclarationsFromOtherModules;
this.checkFunctionContracts = checkFunctionContracts;
this.recursiveFilter = recursiveFilter;
this.validationStrategy = validationStrategy;
this.renderer = renderer;
@@ -322,38 +349,43 @@ public class RecursiveDescriptorComparator {
public Configuration filterRecursion(@NotNull Predicate<DeclarationDescriptor> stepIntoFilter) {
return new Configuration(checkPrimaryConstructors, checkPropertyAccessors, includeMethodsOfKotlinAny,
renderDeclarationsFromOtherModules, stepIntoFilter,
renderDeclarationsFromOtherModules, checkFunctionContracts, stepIntoFilter,
validationStrategy.withStepIntoFilter(stepIntoFilter), renderer);
}
public Configuration checkPrimaryConstructors(boolean checkPrimaryConstructors) {
return new Configuration(checkPrimaryConstructors, checkPropertyAccessors, includeMethodsOfKotlinAny,
renderDeclarationsFromOtherModules, recursiveFilter, validationStrategy, renderer);
renderDeclarationsFromOtherModules, checkFunctionContracts, recursiveFilter, validationStrategy, renderer);
}
public Configuration checkPropertyAccessors(boolean checkPropertyAccessors) {
return new Configuration(checkPrimaryConstructors, checkPropertyAccessors, includeMethodsOfKotlinAny,
renderDeclarationsFromOtherModules, recursiveFilter, validationStrategy, renderer);
renderDeclarationsFromOtherModules, checkFunctionContracts, recursiveFilter, validationStrategy, renderer);
}
public Configuration checkFunctionContracts(boolean checkFunctionContracts) {
return new Configuration(checkPrimaryConstructors, checkPropertyAccessors, includeMethodsOfKotlinAny,
renderDeclarationsFromOtherModules, checkFunctionContracts, recursiveFilter, validationStrategy, renderer);
}
public Configuration includeMethodsOfKotlinAny(boolean includeMethodsOfKotlinAny) {
return new Configuration(checkPrimaryConstructors, checkPropertyAccessors, includeMethodsOfKotlinAny,
renderDeclarationsFromOtherModules, recursiveFilter, validationStrategy, renderer);
renderDeclarationsFromOtherModules, checkFunctionContracts, recursiveFilter, validationStrategy, renderer);
}
public Configuration renderDeclarationsFromOtherModules(boolean renderDeclarationsFromOtherModules) {
return new Configuration(checkPrimaryConstructors, checkPropertyAccessors, includeMethodsOfKotlinAny,
renderDeclarationsFromOtherModules, recursiveFilter, validationStrategy, renderer);
renderDeclarationsFromOtherModules, checkFunctionContracts, recursiveFilter, validationStrategy, renderer);
}
public Configuration withValidationStrategy(@NotNull DescriptorValidator.ValidationVisitor validationStrategy) {
return new Configuration(checkPrimaryConstructors, checkPropertyAccessors, includeMethodsOfKotlinAny,
renderDeclarationsFromOtherModules, recursiveFilter, validationStrategy, renderer);
renderDeclarationsFromOtherModules, checkFunctionContracts, recursiveFilter, validationStrategy, renderer);
}
public Configuration withRenderer(@NotNull DescriptorRenderer renderer) {
return new Configuration(checkPrimaryConstructors, checkPropertyAccessors, includeMethodsOfKotlinAny,
renderDeclarationsFromOtherModules, recursiveFilter, validationStrategy, renderer);
renderDeclarationsFromOtherModules, checkFunctionContracts, recursiveFilter, validationStrategy, renderer);
}
}
}