From 8c0be58f568104c6166df52263f7afdb49083fb6 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Mon, 19 Dec 2016 13:59:23 +0300 Subject: [PATCH] J2K diagnostic tests: convert to Kotlin --- .../checkers/AbstractDiagnosticsTest.kt | 770 ++++++++---------- .../kotlin/checkers/BaseDiagnosticsTest.kt | 752 ++++++++--------- .../AbstractDiagnosticsTestWithJsStdLib.kt | 179 ++-- 3 files changed, 762 insertions(+), 939 deletions(-) diff --git a/compiler/tests-common/org/jetbrains/kotlin/checkers/AbstractDiagnosticsTest.kt b/compiler/tests-common/org/jetbrains/kotlin/checkers/AbstractDiagnosticsTest.kt index 31bfc8226a0..6be7b1bb94c 100644 --- a/compiler/tests-common/org/jetbrains/kotlin/checkers/AbstractDiagnosticsTest.kt +++ b/compiler/tests-common/org/jetbrains/kotlin/checkers/AbstractDiagnosticsTest.kt @@ -14,322 +14,275 @@ * limitations under the License. */ -package org.jetbrains.kotlin.checkers; +package org.jetbrains.kotlin.checkers -import com.google.common.base.Predicate; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Sets; -import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.PsiElement; -import com.intellij.psi.search.GlobalSearchScope; -import junit.framework.TestCase; -import kotlin.TuplesKt; -import kotlin.collections.CollectionsKt; -import kotlin.collections.MapsKt; -import kotlin.jvm.functions.Function1; -import kotlin.jvm.functions.Function2; -import kotlin.text.StringsKt; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.kotlin.analyzer.AnalysisResult; -import org.jetbrains.kotlin.analyzer.ModuleContent; -import org.jetbrains.kotlin.analyzer.ModuleInfo; -import org.jetbrains.kotlin.analyzer.common.DefaultAnalyzerFacade; -import org.jetbrains.kotlin.cli.jvm.compiler.CliLightClassGenerationSupport; -import org.jetbrains.kotlin.cli.jvm.compiler.JvmPackagePartProvider; -import org.jetbrains.kotlin.config.CommonConfigurationKeys; -import org.jetbrains.kotlin.config.CompilerConfiguration; -import org.jetbrains.kotlin.config.LanguageVersionSettings; -import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl; -import org.jetbrains.kotlin.container.ComponentProvider; -import org.jetbrains.kotlin.container.DslKt; -import org.jetbrains.kotlin.context.ContextKt; -import org.jetbrains.kotlin.context.GlobalContext; -import org.jetbrains.kotlin.context.ModuleContext; -import org.jetbrains.kotlin.context.SimpleGlobalContext; -import org.jetbrains.kotlin.descriptors.*; -import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider; -import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl; -import org.jetbrains.kotlin.diagnostics.*; -import org.jetbrains.kotlin.frontend.java.di.InjectionKt; -import org.jetbrains.kotlin.incremental.components.LookupTracker; -import org.jetbrains.kotlin.load.java.lazy.SingleModuleClassResolver; -import org.jetbrains.kotlin.name.FqName; -import org.jetbrains.kotlin.name.Name; -import org.jetbrains.kotlin.name.SpecialNames; -import org.jetbrains.kotlin.platform.JvmBuiltIns; -import org.jetbrains.kotlin.psi.Call; -import org.jetbrains.kotlin.psi.KtElement; -import org.jetbrains.kotlin.psi.KtExpression; -import org.jetbrains.kotlin.psi.KtFile; -import org.jetbrains.kotlin.resolve.*; -import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall; -import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; -import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo; -import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics; -import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver; -import org.jetbrains.kotlin.resolve.jvm.TopDownAnalyzerFacadeForJVM; -import org.jetbrains.kotlin.resolve.lazy.KotlinCodeAnalyzer; -import org.jetbrains.kotlin.resolve.lazy.declarations.FileBasedDeclarationProviderFactory; -import org.jetbrains.kotlin.storage.ExceptionTracker; -import org.jetbrains.kotlin.storage.LockBasedStorageManager; -import org.jetbrains.kotlin.storage.StorageManager; -import org.jetbrains.kotlin.test.InTextDirectivesUtils; -import org.jetbrains.kotlin.test.KotlinTestUtils; -import org.jetbrains.kotlin.test.util.DescriptorValidator; -import org.jetbrains.kotlin.test.util.RecursiveDescriptorComparator; -import org.jetbrains.kotlin.utils.ExceptionUtilsKt; -import org.junit.Assert; +import com.google.common.base.Predicate +import com.google.common.collect.Sets +import com.intellij.openapi.util.io.FileUtil +import com.intellij.openapi.util.text.StringUtil +import com.intellij.psi.PsiElement +import com.intellij.psi.search.GlobalSearchScope +import junit.framework.TestCase +import org.jetbrains.kotlin.analyzer.AnalysisResult +import org.jetbrains.kotlin.analyzer.common.DefaultAnalyzerFacade +import org.jetbrains.kotlin.cli.jvm.compiler.CliLightClassGenerationSupport +import org.jetbrains.kotlin.cli.jvm.compiler.JvmPackagePartProvider +import org.jetbrains.kotlin.config.CommonConfigurationKeys +import org.jetbrains.kotlin.config.CompilerConfiguration +import org.jetbrains.kotlin.config.LanguageVersionSettings +import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl +import org.jetbrains.kotlin.container.getService +import org.jetbrains.kotlin.context.* +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider +import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl +import org.jetbrains.kotlin.diagnostics.* +import org.jetbrains.kotlin.diagnostics.Errors.* +import org.jetbrains.kotlin.frontend.java.di.createContainerForTopDownAnalyzerForJvm +import org.jetbrains.kotlin.frontend.java.di.initJvmBuiltInsForTopDownAnalysis +import org.jetbrains.kotlin.incremental.components.LookupTracker +import org.jetbrains.kotlin.load.java.lazy.SingleModuleClassResolver +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.name.SpecialNames +import org.jetbrains.kotlin.platform.JvmBuiltIns +import org.jetbrains.kotlin.psi.KtExpression +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.resolve.* +import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall +import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo +import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver +import org.jetbrains.kotlin.resolve.jvm.TopDownAnalyzerFacadeForJVM +import org.jetbrains.kotlin.resolve.lazy.KotlinCodeAnalyzer +import org.jetbrains.kotlin.resolve.lazy.declarations.FileBasedDeclarationProviderFactory +import org.jetbrains.kotlin.storage.ExceptionTracker +import org.jetbrains.kotlin.storage.LockBasedStorageManager +import org.jetbrains.kotlin.storage.StorageManager +import org.jetbrains.kotlin.test.InTextDirectivesUtils +import org.jetbrains.kotlin.test.KotlinTestUtils +import org.jetbrains.kotlin.test.util.DescriptorValidator +import org.jetbrains.kotlin.test.util.RecursiveDescriptorComparator +import org.jetbrains.kotlin.test.util.RecursiveDescriptorComparator.* +import org.jetbrains.kotlin.utils.rethrow +import org.junit.Assert +import java.io.File +import java.util.* -import java.io.File; -import java.util.*; +abstract class AbstractDiagnosticsTest : BaseDiagnosticsTest() { + override fun analyzeAndCheck(testDataFile: File, testFiles: List) { + val groupedByModule = testFiles.groupByTo>>( + LinkedHashMap>() + ) { file -> file.module } -import static org.jetbrains.kotlin.diagnostics.Errors.*; -import static org.jetbrains.kotlin.test.util.RecursiveDescriptorComparator.RECURSIVE; -import static org.jetbrains.kotlin.test.util.RecursiveDescriptorComparator.RECURSIVE_ALL; + val checkLazyResolveLog = testFiles.any { file -> file.checkLazyLog } -public abstract class AbstractDiagnosticsTest extends BaseDiagnosticsTest { + var lazyOperationsLog: LazyOperationsLog? = null + val context: GlobalContext - private static final Function1 HASH_SANITIZER = new Function1() { - @Override - public String invoke(String s) { - return s.replaceAll("@(\\d)+", ""); - } - }; - - private static final ModuleDescriptor.Capability> MODULE_FILES = new ModuleDescriptor.Capability>(""); - - @Override - protected void analyzeAndCheck(File testDataFile, List testFiles) { - Map> groupedByModule = CollectionsKt.groupByTo( - testFiles, - new LinkedHashMap>(), - new Function1() { - @Override - public TestModule invoke(TestFile file) { - return file.getModule(); - } - } - ); - - boolean checkLazyResolveLog = CollectionsKt.any(testFiles, new Function1() { - @Override - public Boolean invoke(TestFile file) { - return file.checkLazyLog; - } - }); - - LazyOperationsLog lazyOperationsLog = null; - GlobalContext context; - - ExceptionTracker tracker = new ExceptionTracker(); + val tracker = ExceptionTracker() if (checkLazyResolveLog) { - lazyOperationsLog = new LazyOperationsLog(HASH_SANITIZER); - context = new SimpleGlobalContext( - new LoggingStorageManager( + lazyOperationsLog = LazyOperationsLog(HASH_SANITIZER) + context = SimpleGlobalContext( + LoggingStorageManager( LockBasedStorageManager.createWithExceptionHandling(tracker), - lazyOperationsLog.getAddRecordFunction() + lazyOperationsLog.addRecordFunction ), tracker - ); + ) } else { - context = new SimpleGlobalContext(LockBasedStorageManager.createWithExceptionHandling(tracker), tracker); + context = SimpleGlobalContext(LockBasedStorageManager.createWithExceptionHandling(tracker), tracker) } - Map modules = createModules(groupedByModule, context.getStorageManager()); - Map moduleBindings = new HashMap(); + val modules = createModules(groupedByModule, context.storageManager) + val moduleBindings = java.util.HashMap() - for (Map.Entry> entry : groupedByModule.entrySet()) { - TestModule testModule = entry.getKey(); - List testFilesInModule = entry.getValue(); + for ((testModule, testFilesInModule) in groupedByModule) { - List jetFiles = getJetFiles(testFilesInModule, true); + val jetFiles = getJetFiles(testFilesInModule, true) - ModuleDescriptorImpl oldModule = modules.get(testModule); + val oldModule = modules.get(testModule) - LanguageVersionSettings languageVersionSettings = loadLanguageVersionSettings(testFilesInModule); - ModuleContext moduleContext = ContextKt.withModule(ContextKt.withProject(context, getProject()), oldModule); + val languageVersionSettings = loadLanguageVersionSettings(testFilesInModule) + val moduleContext = context.withProject(project).withModule(oldModule) - boolean separateModules = groupedByModule.size() == 1 && groupedByModule.keySet().iterator().next() == null; - AnalysisResult result = analyzeModuleContents( - moduleContext, jetFiles, new CliLightClassGenerationSupport.NoScopeRecordCliBindingTrace(), + val separateModules = groupedByModule.size == 1 && groupedByModule.keys.iterator().next() == null + val result = analyzeModuleContents( + moduleContext, jetFiles, CliLightClassGenerationSupport.NoScopeRecordCliBindingTrace(), languageVersionSettings, separateModules - ); - ModuleDescriptorImpl newModule = (ModuleDescriptorImpl) result.getModuleDescriptor(); - if (oldModule != newModule) { + ) + if (oldModule != result.moduleDescriptor) { // For common modules, we use DefaultAnalyzerFacade who creates ModuleDescriptor instances by itself // (its API does not support working with a module created beforehand). // So, we should replace the old (effectively discarded) module with the new one everywhere in dependencies. // TODO: dirty hack, refactor this test so that it doesn't create ModuleDescriptor instances - modules.put(testModule, newModule); - for (ModuleDescriptorImpl module : modules.values()) { - @SuppressWarnings("deprecation") - ListIterator it = module.getTestOnly_AllDependentModules().listIterator(); + modules.put(testModule, result.moduleDescriptor) + for (module in modules.values) { + val it = module.testOnly_AllDependentModules.listIterator() while (it.hasNext()) { if (it.next() == oldModule) { - it.set(newModule); + it.set(result.moduleDescriptor) } } } } - moduleBindings.put(testModule, result.getBindingContext()); - checkAllResolvedCallsAreCompleted(jetFiles, result.getBindingContext()); + moduleBindings.put(testModule, result.bindingContext) + checkAllResolvedCallsAreCompleted(jetFiles, result.bindingContext) } // We want to always create a test data file (txt) if it was missing, // but don't want to skip the following checks in case this one fails - Throwable exceptionFromLazyResolveLogValidation = null; + var exceptionFromLazyResolveLogValidation: Throwable? = null if (checkLazyResolveLog) { - exceptionFromLazyResolveLogValidation = checkLazyResolveLog(lazyOperationsLog, testDataFile); + exceptionFromLazyResolveLogValidation = checkLazyResolveLog(lazyOperationsLog, testDataFile) } else { - File lazyLogFile = getLazyLogFile(testDataFile); - TestCase.assertFalse("No lazy log expected, but found: " + lazyLogFile.getAbsolutePath(), lazyLogFile.exists()); + val lazyLogFile = getLazyLogFile(testDataFile) + TestCase.assertFalse("No lazy log expected, but found: " + lazyLogFile.getAbsolutePath(), lazyLogFile.exists()) } - Throwable exceptionFromDescriptorValidation = null; + var exceptionFromDescriptorValidation: Throwable? = null try { - File expectedFile = new File(FileUtil.getNameWithoutExtension(testDataFile.getAbsolutePath()) + ".txt"); - validateAndCompareDescriptorWithFile(expectedFile, testFiles, modules); + val expectedFile = File(FileUtil.getNameWithoutExtension(testDataFile.absolutePath) + ".txt") + validateAndCompareDescriptorWithFile(expectedFile, testFiles, modules) } - catch (Throwable e) { - exceptionFromDescriptorValidation = e; + catch (e: Throwable) { + exceptionFromDescriptorValidation = e } // main checks - boolean ok = true; + var ok = true - StringBuilder actualText = new StringBuilder(); - for (TestFile testFile : testFiles) { - TestModule module = testFile.getModule(); - boolean isCommonModule = MultiTargetPlatformKt.getMultiTargetPlatform(modules.get(module)) == MultiTargetPlatform.Common.INSTANCE; - ok &= testFile.getActualText( + val actualText = StringBuilder() + for (testFile in testFiles) { + val module = testFile.module + val isCommonModule = modules.get(module).getMultiTargetPlatform() === MultiTargetPlatform.Common + ok = ok and testFile.getActualText( moduleBindings.get(module), actualText, shouldSkipJvmSignatureDiagnostics(groupedByModule) || isCommonModule - ); + ) } - Throwable exceptionFromDynamicCallDescriptorsValidation = null; + var exceptionFromDynamicCallDescriptorsValidation: Throwable? = null try { - File expectedFile = new File(FileUtil.getNameWithoutExtension(testDataFile.getAbsolutePath()) + ".dynamic.txt"); - checkDynamicCallDescriptors(expectedFile, testFiles); + val expectedFile = File(FileUtil.getNameWithoutExtension(testDataFile.absolutePath) + ".dynamic.txt") + checkDynamicCallDescriptors(expectedFile, testFiles) } - catch (Throwable e) { - exceptionFromDynamicCallDescriptorsValidation = e; + catch (e: Throwable) { + exceptionFromDynamicCallDescriptorsValidation = e } - KotlinTestUtils.assertEqualsToFile(testDataFile, actualText.toString()); + KotlinTestUtils.assertEqualsToFile(testDataFile, actualText.toString()) - TestCase.assertTrue("Diagnostics mismatch. See the output above", ok); + TestCase.assertTrue("Diagnostics mismatch. See the output above", ok) // now we throw a previously found error, if any if (exceptionFromDescriptorValidation != null) { - throw ExceptionUtilsKt.rethrow(exceptionFromDescriptorValidation); + throw rethrow(exceptionFromDescriptorValidation) } if (exceptionFromLazyResolveLogValidation != null) { - throw ExceptionUtilsKt.rethrow(exceptionFromLazyResolveLogValidation); + throw rethrow(exceptionFromLazyResolveLogValidation) } if (exceptionFromDynamicCallDescriptorsValidation != null) { - throw ExceptionUtilsKt.rethrow(exceptionFromDynamicCallDescriptorsValidation); + throw rethrow(exceptionFromDynamicCallDescriptorsValidation) } - performAdditionalChecksAfterDiagnostics(testDataFile, testFiles, groupedByModule, modules, moduleBindings); + performAdditionalChecksAfterDiagnostics(testDataFile, testFiles, groupedByModule, modules, moduleBindings) } - protected void performAdditionalChecksAfterDiagnostics( - File testDataFile, - List testFiles, - Map> moduleFiles, - Map moduleDescriptors, - Map moduleBindings + protected fun performAdditionalChecksAfterDiagnostics( + testDataFile: File, + testFiles: List, + moduleFiles: Map>, + moduleDescriptors: Map, + moduleBindings: Map ) { // To be overridden by diagnostic-like tests. } - @Nullable - private LanguageVersionSettings loadLanguageVersionSettings(List module) { - LanguageVersionSettings result = null; - for (TestFile file : module) { - LanguageVersionSettings current = file.customLanguageVersionSettings; + private fun loadLanguageVersionSettings(module: List): LanguageVersionSettings? { + var result: LanguageVersionSettings? = null + for (file in module) { + val current = file.customLanguageVersionSettings if (current != null) { - if (result != null && !result.equals(current)) { + if (result != null && result != current) { Assert.fail( "More than one file in the module has " + BaseDiagnosticsTest.LANGUAGE_DIRECTIVE + " or " + BaseDiagnosticsTest.API_VERSION_DIRECTIVE + " directive specified. " + "This is not supported. Please move all directives into one file" - ); + ) } - result = current; + result = current } } - return result; + return result } - private void checkDynamicCallDescriptors(File expectedFile, List testFiles) { - RecursiveDescriptorComparator serializer = new RecursiveDescriptorComparator(RECURSIVE_ALL); + private fun checkDynamicCallDescriptors(expectedFile: File, testFiles: List) { + val serializer = RecursiveDescriptorComparator(RECURSIVE_ALL) - StringBuilder actualText = new StringBuilder(); + val actualText = StringBuilder() - for (TestFile testFile : testFiles) { - List dynamicCallDescriptors = testFile.getDynamicCallDescriptors(); + for (testFile in testFiles) { + val dynamicCallDescriptors = testFile.dynamicCallDescriptors - for (DeclarationDescriptor descriptor : dynamicCallDescriptors) { - String actualSerialized = serializer.serializeRecursively(descriptor); - actualText.append(actualSerialized); + for (descriptor in dynamicCallDescriptors) { + val actualSerialized = serializer.serializeRecursively(descriptor) + actualText.append(actualSerialized) } } - if (actualText.length() != 0 || expectedFile.exists()) { - KotlinTestUtils.assertEqualsToFile(expectedFile, actualText.toString()); + if (actualText.length != 0 || expectedFile.exists()) { + KotlinTestUtils.assertEqualsToFile(expectedFile, actualText.toString()) } } - public boolean shouldSkipJvmSignatureDiagnostics(Map> groupedByModule) { - return groupedByModule.size() > 1; + fun shouldSkipJvmSignatureDiagnostics(groupedByModule: Map>): Boolean { + return groupedByModule.size > 1 } - @Nullable - private static Throwable checkLazyResolveLog(LazyOperationsLog lazyOperationsLog, File testDataFile) { - Throwable exceptionFromLazyResolveLogValidation = null; + private fun checkLazyResolveLog(lazyOperationsLog: LazyOperationsLog, testDataFile: File): Throwable? { + var exceptionFromLazyResolveLogValidation: Throwable? = null try { - File expectedFile = getLazyLogFile(testDataFile); + val expectedFile = getLazyLogFile(testDataFile) KotlinTestUtils.assertEqualsToFile( expectedFile, lazyOperationsLog.getText(), HASH_SANITIZER - ); + ) } - catch (Throwable e) { - exceptionFromLazyResolveLogValidation = e; + catch (e: Throwable) { + exceptionFromLazyResolveLogValidation = e } - return exceptionFromLazyResolveLogValidation; + + return exceptionFromLazyResolveLogValidation } - private static File getLazyLogFile(File testDataFile) { - return new File(FileUtil.getNameWithoutExtension(testDataFile.getAbsolutePath()) + ".lazy.log"); + private fun getLazyLogFile(testDataFile: File): File { + return File(FileUtil.getNameWithoutExtension(testDataFile.absolutePath) + ".lazy.log") } - @NotNull - protected AnalysisResult analyzeModuleContents( - @NotNull ModuleContext moduleContext, - @NotNull List files, - @NotNull BindingTrace moduleTrace, - @Nullable LanguageVersionSettings languageVersionSettings, - boolean separateModules - ) { - CompilerConfiguration configuration; + protected fun analyzeModuleContents( + moduleContext: ModuleContext, + files: List, + moduleTrace: BindingTrace, + languageVersionSettings: LanguageVersionSettings?, + separateModules: Boolean + ): AnalysisResult { + var files = files + var languageVersionSettings = languageVersionSettings + val configuration: CompilerConfiguration if (languageVersionSettings != null) { - configuration = getEnvironment().getConfiguration().copy(); - configuration.put(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS, languageVersionSettings); + configuration = environment.configuration.copy() + configuration.put(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS, languageVersionSettings) } else { - configuration = getEnvironment().getConfiguration(); - languageVersionSettings = LanguageVersionSettingsImpl.DEFAULT; + configuration = environment.configuration + languageVersionSettings = LanguageVersionSettingsImpl.DEFAULT } // New JavaDescriptorResolver is created for each module, which is good because it emulates different Java libraries for each module, @@ -341,300 +294,281 @@ public abstract class AbstractDiagnosticsTest extends BaseDiagnosticsTest { // TODO: always use separate module mode, once analyzeFilesWithJavaIntegration can create multiple modules if (separateModules) { return TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration( - moduleContext.getProject(), + moduleContext.project, files, moduleTrace, configuration, - new Function1() { - @Override - public PackagePartProvider invoke(GlobalSearchScope scope) { - return new JvmPackagePartProvider(getEnvironment(), scope); - } - } - ); + { scope -> JvmPackagePartProvider(environment, scope) } + ) } - ModuleDescriptorImpl moduleDescriptor = (ModuleDescriptorImpl) moduleContext.getModule(); + val moduleDescriptor = moduleContext.module as ModuleDescriptorImpl - MultiTargetPlatform platform = MultiTargetPlatformKt.getMultiTargetPlatform(moduleDescriptor); - if (platform == MultiTargetPlatform.Common.INSTANCE) { - //noinspection unchecked - return DefaultAnalyzerFacade.INSTANCE.analyzeFiles( - files, moduleDescriptor.getName(), true, - MapsKt.mapOf( - TuplesKt.to(MultiTargetPlatform.CAPABILITY, MultiTargetPlatform.Common.INSTANCE), - TuplesKt.to(MODULE_FILES, files) - ), - new Function2() { - @Override - public PackagePartProvider invoke(ModuleInfo info, ModuleContent content) { - // TODO - return PackagePartProvider.Empty.INSTANCE; - } - } - ); + val platform = moduleDescriptor.getMultiTargetPlatform() + if (platform === MultiTargetPlatform.Common) { + + return DefaultAnalyzerFacade.analyzeFiles( + files, moduleDescriptor.name, true, + mapOf, Any>( + MultiTargetPlatform.CAPABILITY.to, MultiTargetPlatform.Common>(MultiTargetPlatform.Common), + MODULE_FILES.to>, List>(files) + ) + ) { info, content -> + // TODO + PackagePartProvider.Empty + } } else if (platform != null) { // TODO: analyze with the correct platform, not always JVM - files = CollectionsKt.plus(files, getCommonCodeFilesForPlatformSpecificModule(moduleDescriptor)); + files = files.plus(getCommonCodeFilesForPlatformSpecificModule(moduleDescriptor)) } - GlobalSearchScope moduleContentScope = GlobalSearchScope.allScope(moduleContext.getProject()); - SingleModuleClassResolver moduleClassResolver = new SingleModuleClassResolver(); - ComponentProvider container = InjectionKt.createContainerForTopDownAnalyzerForJvm( + val moduleContentScope = GlobalSearchScope.allScope(moduleContext.project) + val moduleClassResolver = SingleModuleClassResolver() + val container = createContainerForTopDownAnalyzerForJvm( moduleContext, moduleTrace, - new FileBasedDeclarationProviderFactory(moduleContext.getStorageManager(), files), + FileBasedDeclarationProviderFactory(moduleContext.storageManager, files), moduleContentScope, - LookupTracker.Companion.getDO_NOTHING(), - new JvmPackagePartProvider(getEnvironment(), moduleContentScope), + LookupTracker.DO_NOTHING, + JvmPackagePartProvider(environment, moduleContentScope), languageVersionSettings, moduleClassResolver - ); - InjectionKt.initJvmBuiltInsForTopDownAnalysis(container, moduleDescriptor, languageVersionSettings); - moduleClassResolver.setResolver(DslKt.getService(container, JavaDescriptorResolver.class)); + ) + container.initJvmBuiltInsForTopDownAnalysis(moduleDescriptor, languageVersionSettings) + moduleClassResolver.resolver = container.getService(JavaDescriptorResolver::class.java) - moduleDescriptor.initialize(new CompositePackageFragmentProvider(Arrays.asList( - DslKt.getService(container, KotlinCodeAnalyzer.class).getPackageFragmentProvider(), - DslKt.getService(container, JavaDescriptorResolver.class).getPackageFragmentProvider() - ))); + moduleDescriptor.initialize(CompositePackageFragmentProvider(Arrays.asList( + container.getService(KotlinCodeAnalyzer::class.java).getPackageFragmentProvider(), + container.getService(JavaDescriptorResolver::class.java).packageFragmentProvider + ))) - DslKt.getService(container, LazyTopDownAnalyzer.class).analyzeDeclarations( - TopDownAnalysisMode.TopLevelDeclarations, files, DataFlowInfo.Companion.getEMPTY() - ); + container.getService(LazyTopDownAnalyzer::class.java).analyzeDeclarations( + TopDownAnalysisMode.TopLevelDeclarations, files, DataFlowInfo.EMPTY + ) - return AnalysisResult.success(moduleTrace.getBindingContext(), moduleDescriptor); + return AnalysisResult.success(moduleTrace.bindingContext, moduleDescriptor) } - @NotNull - private static List getCommonCodeFilesForPlatformSpecificModule(@NotNull ModuleDescriptorImpl moduleDescriptor) { + private fun getCommonCodeFilesForPlatformSpecificModule(moduleDescriptor: ModuleDescriptorImpl): List { // We assume that a platform-specific module _implements_ all declarations from common modules which are immediate dependencies. // So we collect all sources from such modules to analyze in the platform-specific module as well - @SuppressWarnings("deprecation") - List dependencies = moduleDescriptor.getTestOnly_AllDependentModules(); + val dependencies = moduleDescriptor.testOnly_AllDependentModules // TODO: diagnostics on common code reported during the platform module analysis should be distinguished somehow // E.g. "... - List result = new ArrayList(0); - for (ModuleDescriptorImpl dependency : dependencies) { - if (dependency.getCapability(MultiTargetPlatform.CAPABILITY) == MultiTargetPlatform.Common.INSTANCE) { - List files = dependency.getCapability(MODULE_FILES); - assert files != null : "MODULE_FILES should have been set for the common module: " + dependency; - result.addAll(files); + val result = ArrayList(0) + for (dependency in dependencies) { + if (dependency.getCapability(MultiTargetPlatform.CAPABILITY) === MultiTargetPlatform.Common) { + val files = dependency.getCapability(MODULE_FILES) ?: error("MODULE_FILES should have been set for the common module: " + dependency) + result.addAll(files) } } - return result; + return result } - private void validateAndCompareDescriptorWithFile( - File expectedFile, - List testFiles, - Map modules + private fun validateAndCompareDescriptorWithFile( + expectedFile: File, + testFiles: List, + modules: Map ) { - if (CollectionsKt.any(testFiles, new Function1() { - @Override - public Boolean invoke(TestFile file) { - return InTextDirectivesUtils.isDirectiveDefined(file.expectedText, "// SKIP_TXT"); - } - })) { - TestCase.assertFalse(".txt file should not exist if SKIP_TXT directive is used: " + expectedFile, expectedFile.exists()); - return; + if (testFiles.any { file -> InTextDirectivesUtils.isDirectiveDefined(file.expectedText, "// SKIP_TXT") }) { + TestCase.assertFalse(".txt file should not exist if SKIP_TXT directive is used: " + expectedFile, expectedFile.exists()) + return } - RecursiveDescriptorComparator comparator = new RecursiveDescriptorComparator(createdAffectedPackagesConfiguration(testFiles, modules.values())); + val comparator = RecursiveDescriptorComparator(createdAffectedPackagesConfiguration(testFiles, modules.values)) - boolean isMultiModuleTest = modules.size() != 1; - StringBuilder rootPackageText = new StringBuilder(); + val isMultiModuleTest = modules.size != 1 + val rootPackageText = StringBuilder() - for (Iterator module = CollectionsKt.sorted(modules.keySet()).iterator(); module.hasNext(); ) { - ModuleDescriptorImpl moduleDescriptor = modules.get(module.next()); - PackageViewDescriptor aPackage = moduleDescriptor.getPackage(FqName.ROOT); - TestCase.assertFalse(aPackage.isEmpty()); + val module = modules.keys.sorted().iterator() + while (module.hasNext()) { + val moduleDescriptor = modules[module.next()] + val aPackage = moduleDescriptor.getPackage(FqName.ROOT) + TestCase.assertFalse(aPackage.isEmpty()) if (isMultiModuleTest) { - rootPackageText.append(String.format("// -- Module: %s --\n", moduleDescriptor.getName())); + rootPackageText.append(String.format("// -- Module: %s --\n", moduleDescriptor.getName())) } - String actualSerialized = comparator.serializeRecursively(aPackage); - rootPackageText.append(actualSerialized); + val actualSerialized = comparator.serializeRecursively(aPackage) + rootPackageText.append(actualSerialized) if (isMultiModuleTest && module.hasNext()) { - rootPackageText.append("\n\n"); + rootPackageText.append("\n\n") } } - int lineCount = StringUtil.getLineBreakCount(rootPackageText); - assert lineCount < 1000 : - "Rendered descriptors of this test take up " + lineCount + " lines. " + - "Please ensure you don't render JRE contents to the .txt file. " + - "Such tests are hard to maintain, take long time to execute and are subject to sudden unreviewed changes anyway."; - - KotlinTestUtils.assertEqualsToFile(expectedFile, rootPackageText.toString()); - } - - private RecursiveDescriptorComparator.Configuration createdAffectedPackagesConfiguration(List testFiles, final Collection modules) { - final Set packagesNames = getTopLevelPackagesFromFileList(getJetFiles(testFiles, false)); - - Predicate stepIntoFilter = new Predicate() { - @Override - public boolean apply(DeclarationDescriptor descriptor) { - ModuleDescriptor module = DescriptorUtils.getContainingModuleOrNull(descriptor); - if (!modules.contains(module)) return false; - - if (descriptor instanceof PackageViewDescriptor) { - FqName fqName = ((PackageViewDescriptor) descriptor).getFqName(); - - if (fqName.isRoot()) return true; - - Name firstName = fqName.pathSegments().get(0); - return packagesNames.contains(firstName); - } - - return true; - } - }; - - return RECURSIVE.filterRecursion(stepIntoFilter).withValidationStrategy(DescriptorValidator.ValidationVisitor.errorTypesAllowed()); - } - - @NotNull - private static Set getTopLevelPackagesFromFileList(@NotNull List files) { - Set shortNames = new LinkedHashSet(); - for (KtFile file : files) { - List packageFqNameSegments = file.getPackageFqName().pathSegments(); - Name name = packageFqNameSegments.isEmpty() ? SpecialNames.ROOT_PACKAGE : packageFqNameSegments.get(0); - shortNames.add(name); - } - return shortNames; - } - - private Map createModules( - @NotNull Map> groupedByModule, - @NotNull StorageManager storageManager - ) { - Map modules = new HashMap(); - - for (TestModule testModule : groupedByModule.keySet()) { - ModuleDescriptorImpl module = - testModule == null ? - createSealedModule(storageManager) : - createModule(testModule.getName(), storageManager); - - modules.put(testModule, module); + val lineCount = StringUtil.getLineBreakCount(rootPackageText) + assert(lineCount < 1000) { + "Rendered descriptors of this test take up " + lineCount + " lines. " + + "Please ensure you don't render JRE contents to the .txt file. " + + "Such tests are hard to maintain, take long time to execute and are subject to sudden unreviewed changes anyway." } - for (TestModule testModule : groupedByModule.keySet()) { - if (testModule == null) continue; + KotlinTestUtils.assertEqualsToFile(expectedFile, rootPackageText.toString()) + } - ModuleDescriptorImpl module = modules.get(testModule); - List dependencies = new ArrayList(); - dependencies.add(module); - for (TestModule dependency : testModule.getDependencies()) { - dependencies.add(modules.get(dependency)); + private fun createdAffectedPackagesConfiguration(testFiles: List, modules: Collection): RecursiveDescriptorComparator.Configuration { + val packagesNames = getTopLevelPackagesFromFileList(getJetFiles(testFiles, false)) + + val stepIntoFilter = Predicate { descriptor -> + val module = DescriptorUtils.getContainingModuleOrNull(descriptor!!) + if (!modules.contains(module)) return@Predicate false + + if (descriptor is PackageViewDescriptor) { + val fqName = descriptor.fqName + + if (fqName.isRoot) return@Predicate true + + val firstName = fqName.pathSegments()[0] + return@Predicate packagesNames.contains(firstName) } - dependencies.add(module.getBuiltIns().getBuiltInsModule()); - dependencies.addAll(getAdditionalDependencies(module)); - module.setDependencies(dependencies); + true } - return modules; + return RECURSIVE.filterRecursion(stepIntoFilter).withValidationStrategy(DescriptorValidator.ValidationVisitor.errorTypesAllowed()) } - @NotNull - protected List getAdditionalDependencies(@NotNull ModuleDescriptorImpl module) { - return Collections.emptyList(); + private fun getTopLevelPackagesFromFileList(files: List): Set { + val shortNames = LinkedHashSet() + for (file in files) { + val packageFqNameSegments = file.packageFqName.pathSegments() + val name = if (packageFqNameSegments.isEmpty()) SpecialNames.ROOT_PACKAGE else packageFqNameSegments[0] + shortNames.add(name) + } + return shortNames } - @NotNull - @SuppressWarnings("unchecked") - protected ModuleDescriptorImpl createModule(@NotNull String moduleName, @NotNull StorageManager storageManager) { - String nameSuffix = StringsKt.substringAfterLast(moduleName, "-", ""); - MultiTargetPlatform platform = - nameSuffix.isEmpty() ? null : - nameSuffix.equals("common") ? MultiTargetPlatform.Common.INSTANCE : new MultiTargetPlatform.Specific(nameSuffix); - Map capabilities = - platform == null - ? Collections.emptyMap() - : Collections.singletonMap(MultiTargetPlatform.CAPABILITY, platform); - return new ModuleDescriptorImpl( - Name.special("<" + moduleName + ">"), storageManager, new JvmBuiltIns(storageManager), - platform == MultiTargetPlatform.Common.INSTANCE ? PlatformKind.DEFAULT : PlatformKind.JVM, + private fun createModules( + groupedByModule: Map>, + storageManager: StorageManager + ): Map { + val modules = HashMap() + + for (testModule in groupedByModule.keys) { + val module = if (testModule == null) + createSealedModule(storageManager) + else + createModule(testModule.name, storageManager) + + modules.put(testModule, module) + } + + for (testModule in groupedByModule.keys) { + if (testModule == null) continue + + val module = modules[testModule] + val dependencies = ArrayList() + dependencies.add(module) + for (dependency in testModule.getDependencies()) { + dependencies.add(modules[dependency]) + } + + dependencies.add(module.builtIns.builtInsModule) + dependencies.addAll(getAdditionalDependencies(module)) + module.setDependencies(dependencies) + } + + return modules + } + + protected fun getAdditionalDependencies(module: ModuleDescriptorImpl): List { + return emptyList() + } + + protected fun createModule(moduleName: String, storageManager: StorageManager): ModuleDescriptorImpl { + val nameSuffix = moduleName.substringAfterLast("-", "") + val platform = if (nameSuffix.isEmpty()) + null + else if (nameSuffix == "common") MultiTargetPlatform.Common else MultiTargetPlatform.Specific(nameSuffix) + val capabilities = if (platform == null) + emptyMap() + else + Collections.singletonMap, MultiTargetPlatform>(MultiTargetPlatform.CAPABILITY, platform) + return ModuleDescriptorImpl( + Name.special("<$moduleName>"), storageManager, JvmBuiltIns(storageManager), + if (platform === MultiTargetPlatform.Common) PlatformKind.DEFAULT else PlatformKind.JVM, SourceKind.TEST, capabilities - ); + ) } - @NotNull - protected ModuleDescriptorImpl createSealedModule(@NotNull StorageManager storageManager) { - ModuleDescriptorImpl moduleDescriptor = createModule("test-module", storageManager); - moduleDescriptor.setDependencies(moduleDescriptor, moduleDescriptor.getBuiltIns().getBuiltInsModule()); - return moduleDescriptor; + protected fun createSealedModule(storageManager: StorageManager): ModuleDescriptorImpl { + val moduleDescriptor = createModule("test-module", storageManager) + moduleDescriptor.setDependencies(moduleDescriptor, moduleDescriptor.builtIns.builtInsModule) + return moduleDescriptor } - private static void checkAllResolvedCallsAreCompleted(@NotNull List jetFiles, @NotNull BindingContext bindingContext) { - for (KtFile file : jetFiles) { + private fun checkAllResolvedCallsAreCompleted(jetFiles: List, bindingContext: BindingContext) { + for (file in jetFiles) { if (!AnalyzingUtils.getSyntaxErrorRanges(file).isEmpty()) { - return; + return } } - ImmutableMap> resolvedCallsEntries = bindingContext.getSliceContents(BindingContext.RESOLVED_CALL); - for (Map.Entry> entry : resolvedCallsEntries.entrySet()) { - KtElement element = entry.getKey().getCallElement(); - ResolvedCall resolvedCall = entry.getValue(); + val resolvedCallsEntries = bindingContext.getSliceContents(BindingContext.RESOLVED_CALL) + for (entry in resolvedCallsEntries.entries) { + val element = entry.key.callElement + val resolvedCall = entry.value - DiagnosticUtils.LineAndColumn lineAndColumn = - DiagnosticUtils.getLineAndColumnInPsiFile(element.getContainingFile(), element.getTextRange()); + val lineAndColumn = DiagnosticUtils.getLineAndColumnInPsiFile(element.containingFile, element.textRange) - TestCase.assertTrue("Resolved call for '" + element.getText() + "'" + lineAndColumn + " is not completed", - ((MutableResolvedCall) resolvedCall).isCompleted()); + TestCase.assertTrue("Resolved call for '" + element.text + "'" + lineAndColumn + " is not completed", + (resolvedCall as MutableResolvedCall<*>).isCompleted) } - checkResolvedCallsInDiagnostics(bindingContext); + checkResolvedCallsInDiagnostics(bindingContext) } - @SuppressWarnings({"unchecked", "ConstantConditions"}) - private static void checkResolvedCallsInDiagnostics(BindingContext bindingContext) { - Set>>> diagnosticsStoringResolvedCalls1 = Sets.newHashSet( + private fun checkResolvedCallsInDiagnostics(bindingContext: BindingContext) { + val diagnosticsStoringResolvedCalls1 = Sets.newHashSet>>>( OVERLOAD_RESOLUTION_AMBIGUITY, NONE_APPLICABLE, CANNOT_COMPLETE_RESOLVE, UNRESOLVED_REFERENCE_WRONG_RECEIVER, - ASSIGN_OPERATOR_AMBIGUITY, ITERATOR_AMBIGUITY); - Set>, Collection>>> - diagnosticsStoringResolvedCalls2 = Sets.newHashSet( - COMPONENT_FUNCTION_AMBIGUITY, DELEGATE_SPECIAL_FUNCTION_AMBIGUITY, DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE); - Diagnostics diagnostics = bindingContext.getDiagnostics(); - for (Diagnostic diagnostic : diagnostics) { - DiagnosticFactory factory = diagnostic.getFactory(); - //noinspection SuspiciousMethodCalls + ASSIGN_OPERATOR_AMBIGUITY, ITERATOR_AMBIGUITY) + val diagnosticsStoringResolvedCalls2 = Sets.newHashSet>, Collection>>>( + COMPONENT_FUNCTION_AMBIGUITY, DELEGATE_SPECIAL_FUNCTION_AMBIGUITY, DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE) + val diagnostics = bindingContext.diagnostics + for (diagnostic in diagnostics) { + val factory = diagnostic.factory + if (diagnosticsStoringResolvedCalls1.contains(factory)) { assertResolvedCallsAreCompleted( - diagnostic, DiagnosticFactory.cast(diagnostic, diagnosticsStoringResolvedCalls1).getA()); + diagnostic, DiagnosticFactory.cast(diagnostic, diagnosticsStoringResolvedCalls1).a) } - //noinspection SuspiciousMethodCalls + if (diagnosticsStoringResolvedCalls2.contains(factory)) { assertResolvedCallsAreCompleted( diagnostic, - DiagnosticFactory.cast(diagnostic, diagnosticsStoringResolvedCalls2).getB()); + DiagnosticFactory.cast>, Collection>>>(diagnostic, diagnosticsStoringResolvedCalls2).b) } } } - private static void assertResolvedCallsAreCompleted( - @NotNull Diagnostic diagnostic, @NotNull Collection> resolvedCalls + private fun assertResolvedCallsAreCompleted( + diagnostic: Diagnostic, resolvedCalls: Collection> ) { - boolean allCallsAreCompleted = true; - for (ResolvedCall resolvedCall : resolvedCalls) { - if (!((MutableResolvedCall) resolvedCall).isCompleted()) { - allCallsAreCompleted = false; + var allCallsAreCompleted = true + for (resolvedCall in resolvedCalls) { + if (!(resolvedCall as MutableResolvedCall<*>).isCompleted) { + allCallsAreCompleted = false } } - PsiElement element = diagnostic.getPsiElement(); - DiagnosticUtils.LineAndColumn lineAndColumn = - DiagnosticUtils.getLineAndColumnInPsiFile(element.getContainingFile(), element.getTextRange()); + val element = diagnostic.psiElement + val lineAndColumn = DiagnosticUtils.getLineAndColumnInPsiFile(element.containingFile, element.textRange) - TestCase.assertTrue("Resolved calls stored in " + diagnostic.getFactory().getName() + "\n" + - "for '" + element.getText() + "'" + lineAndColumn + " are not completed", - allCallsAreCompleted); + TestCase.assertTrue("Resolved calls stored in " + diagnostic.factory.name + "\n" + + "for '" + element.text + "'" + lineAndColumn + " are not completed", + allCallsAreCompleted) + } + + companion object { + private val HASH_SANITIZER = fun(s: String): String { + return s.replace("@(\\d)+".toRegex(), "") + } + + private val MODULE_FILES = ModuleDescriptor.Capability>("") } } diff --git a/compiler/tests-common/org/jetbrains/kotlin/checkers/BaseDiagnosticsTest.kt b/compiler/tests-common/org/jetbrains/kotlin/checkers/BaseDiagnosticsTest.kt index eb2dcfb0e07..c8e23743f60 100644 --- a/compiler/tests-common/org/jetbrains/kotlin/checkers/BaseDiagnosticsTest.kt +++ b/compiler/tests-common/org/jetbrains/kotlin/checkers/BaseDiagnosticsTest.kt @@ -14,515 +14,423 @@ * limitations under the License. */ -package org.jetbrains.kotlin.checkers; +package org.jetbrains.kotlin.checkers -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Lists; -import com.intellij.lang.java.JavaLanguage; -import com.intellij.openapi.util.Condition; -import com.intellij.openapi.util.Conditions; -import com.intellij.openapi.util.TextRange; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiFileFactory; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.util.Function; -import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.containers.HashMap; -import kotlin.collections.CollectionsKt; -import kotlin.jvm.functions.Function1; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.kotlin.asJava.DuplicateJvmSignatureUtilKt; -import org.jetbrains.kotlin.config.*; -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; -import org.jetbrains.kotlin.diagnostics.*; -import org.jetbrains.kotlin.load.java.InternalFlexibleTypeTransformer; -import org.jetbrains.kotlin.psi.KtDeclaration; -import org.jetbrains.kotlin.psi.KtFile; -import org.jetbrains.kotlin.resolve.BindingContext; -import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics; -import org.jetbrains.kotlin.test.KotlinTestUtils; -import org.jetbrains.kotlin.utils.StringsKt; -import org.junit.Assert; +import com.google.common.collect.ImmutableSet +import com.google.common.collect.Lists +import com.intellij.lang.java.JavaLanguage +import com.intellij.openapi.util.Condition +import com.intellij.openapi.util.Conditions +import com.intellij.openapi.util.TextRange +import com.intellij.psi.PsiFile +import com.intellij.psi.PsiFileFactory +import com.intellij.psi.search.GlobalSearchScope +import com.intellij.psi.util.PsiTreeUtil +import com.intellij.util.Function +import com.intellij.util.containers.ContainerUtil +import com.intellij.util.containers.HashMap +import org.jetbrains.kotlin.asJava.* +import org.jetbrains.kotlin.config.* +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.diagnostics.* +import org.jetbrains.kotlin.load.java.InternalFlexibleTypeTransformer +import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics +import org.jetbrains.kotlin.test.KotlinTestUtils +import org.jetbrains.kotlin.utils.* +import org.junit.Assert -import java.io.File; -import java.util.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; +import java.io.File +import java.util.* +import java.util.regex.Matcher +import java.util.regex.Pattern -public abstract class BaseDiagnosticsTest - extends KotlinMultiFileTestWithJava { +abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava() { - public static final String DIAGNOSTICS_DIRECTIVE = "DIAGNOSTICS"; - public static final Pattern DIAGNOSTICS_PATTERN = Pattern.compile("([\\+\\-!])(\\w+)\\s*"); - public static final ImmutableSet> DIAGNOSTICS_TO_INCLUDE_ANYWAY = - ImmutableSet.of( - Errors.UNRESOLVED_REFERENCE, - Errors.UNRESOLVED_REFERENCE_WRONG_RECEIVER, - CheckerTestUtil.SyntaxErrorDiagnosticFactory.INSTANCE, - CheckerTestUtil.DebugInfoDiagnosticFactory.ELEMENT_WITH_ERROR_TYPE, - CheckerTestUtil.DebugInfoDiagnosticFactory.MISSING_UNRESOLVED, - CheckerTestUtil.DebugInfoDiagnosticFactory.UNRESOLVED_WITH_TARGET - ); - - public static final String LANGUAGE_DIRECTIVE = "LANGUAGE"; - private static final Pattern LANGUAGE_PATTERN = Pattern.compile("([\\+\\-])(\\w+)\\s*"); - - public static final String API_VERSION_DIRECTIVE = "API_VERSION"; - - public static final String CHECK_TYPE_DIRECTIVE = "CHECK_TYPE"; - public static final String CHECK_TYPE_PACKAGE = "tests._checkType"; - private static final String CHECK_TYPE_DECLARATIONS = "\npackage " + CHECK_TYPE_PACKAGE + - "\nfun checkSubtype(t: T) = t" + - "\nclass Inv" + - "\nfun Inv._() {}" + - "\ninfix fun T.checkType(f: Inv.() -> Unit) {}"; - public static final String CHECK_TYPE_IMPORT = "import " + CHECK_TYPE_PACKAGE + ".*"; - - public static final String EXPLICIT_FLEXIBLE_TYPES_DIRECTIVE = "EXPLICIT_FLEXIBLE_TYPES"; - public static final String EXPLICIT_FLEXIBLE_PACKAGE = InternalFlexibleTypeTransformer.FLEXIBLE_TYPE_CLASSIFIER.getPackageFqName().asString(); - public static final String EXPLICIT_FLEXIBLE_CLASS_NAME = InternalFlexibleTypeTransformer.FLEXIBLE_TYPE_CLASSIFIER.getRelativeClassName().asString(); - private static final String EXPLICIT_FLEXIBLE_TYPES_DECLARATIONS - = "\npackage " + EXPLICIT_FLEXIBLE_PACKAGE + - "\npublic class " + EXPLICIT_FLEXIBLE_CLASS_NAME + ""; - private static final String EXPLICIT_FLEXIBLE_TYPES_IMPORT = "import " + EXPLICIT_FLEXIBLE_PACKAGE + "." + EXPLICIT_FLEXIBLE_CLASS_NAME; - public static final String CHECK_LAZY_LOG_DIRECTIVE = "CHECK_LAZY_LOG"; - public static final boolean CHECK_LAZY_LOG_DEFAULT = "true".equals(System.getProperty("check.lazy.logs", "false")); - - public static final String MARK_DYNAMIC_CALLS_DIRECTIVE = "MARK_DYNAMIC_CALLS"; - - @Override - protected TestModule createTestModule(@NotNull String name) { - return new TestModule(name); + override fun createTestModule(name: String): TestModule { + return TestModule(name) } - @Override - protected TestFile createTestFile(TestModule module, String fileName, String text, Map directives) { - return new TestFile(module, fileName, text, directives); + override fun createTestFile(module: TestModule, fileName: String, text: String, directives: Map): TestFile { + return TestFile(module, fileName, text, directives) } - @Override - protected void doMultiFileTest(File file, final Map modules, List testFiles) { - for (final ModuleAndDependencies moduleAndDependencies : modules.values()) { - List dependencies = CollectionsKt.map( - moduleAndDependencies.dependencies, - new Function1() { - @Override - public TestModule invoke(String name) { - ModuleAndDependencies dependency = modules.get(name); - assert dependency != null : "Dependency not found: " + - name + - " for module " + - moduleAndDependencies.module.getName(); - return dependency.module; - } + override fun doMultiFileTest(file: File, modules: Map.ModuleAndDependencies>, testFiles: List) { + for (moduleAndDependencies in modules.values) { + val dependencies = moduleAndDependencies.dependencies.map( + { name -> + val dependency = modules[name] ?: error("Dependency not found: " + + name + + " for module " + + moduleAndDependencies.module.name) + dependency.module } - ); - moduleAndDependencies.module.getDependencies().addAll(dependencies); + ) + moduleAndDependencies.module.getDependencies().addAll(dependencies) } - analyzeAndCheck(file, testFiles); + analyzeAndCheck(file, testFiles) } - protected abstract void analyzeAndCheck( - File testDataFile, - List files - ); + protected abstract fun analyzeAndCheck( + testDataFile: File, + files: List + ) - protected List getJetFiles(List testFiles, boolean includeExtras) { - boolean declareFlexibleType = false; - boolean declareCheckType = false; - List jetFiles = Lists.newArrayList(); - for (TestFile testFile : testFiles) { - if (testFile.getJetFile() != null) { - jetFiles.add(testFile.getJetFile()); + protected fun getJetFiles(testFiles: List, includeExtras: Boolean): List { + var declareFlexibleType = false + var declareCheckType = false + val jetFiles = Lists.newArrayList() + for (testFile in testFiles) { + if (testFile.jetFile != null) { + jetFiles.add(testFile.jetFile) } - declareFlexibleType |= testFile.declareFlexibleType; - declareCheckType |= testFile.declareCheckType; + declareFlexibleType = declareFlexibleType or testFile.declareFlexibleType + declareCheckType = declareCheckType or testFile.declareCheckType } if (includeExtras) { if (declareFlexibleType) { - jetFiles.add(KotlinTestUtils.createFile("EXPLICIT_FLEXIBLE_TYPES.kt", EXPLICIT_FLEXIBLE_TYPES_DECLARATIONS, getProject())); + jetFiles.add(KotlinTestUtils.createFile("EXPLICIT_FLEXIBLE_TYPES.kt", EXPLICIT_FLEXIBLE_TYPES_DECLARATIONS, project)) } if (declareCheckType) { - jetFiles.add(KotlinTestUtils.createFile("CHECK_TYPE.kt", CHECK_TYPE_DECLARATIONS, getProject())); + jetFiles.add(KotlinTestUtils.createFile("CHECK_TYPE.kt", CHECK_TYPE_DECLARATIONS, project)) } } - return jetFiles; + return jetFiles } - @Nullable - private static LanguageVersionSettings parseLanguageVersionSettings(Map directiveMap) { - String apiVersionString = directiveMap.get(API_VERSION_DIRECTIVE); - String directives = directiveMap.get(LANGUAGE_DIRECTIVE); - if (apiVersionString == null && directives == null) return null; + class TestModule(val name: String) : Comparable { + private val dependencies = ArrayList() - ApiVersion apiVersion = apiVersionString != null ? ApiVersion.Companion.parse(apiVersionString) : ApiVersion.LATEST; - assert apiVersion != null : "Unknown API version: " + apiVersionString; - - Map languageFeatures = - directives == null ? Collections.emptyMap() : collectLanguageFeatureMap(directives); - - return new DiagnosticTestLanguageVersionSettings(languageFeatures, apiVersion); - } - - @NotNull - private static Map collectLanguageFeatureMap(@NotNull String directives) { - Matcher matcher = LANGUAGE_PATTERN.matcher(directives); - if (!matcher.find()) { - Assert.fail( - "Wrong syntax in the '// !" + LANGUAGE_DIRECTIVE + ": ...' directive:\n" + - "found: '" + directives + "'\n" + - "Must be '([+-]LanguageFeatureName)+'\n" + - "where '+' means 'enable' and '-' means 'disable'\n" + - "and language feature names are names of enum entries in LanguageFeature enum class" - ); + fun getDependencies(): MutableList { + return dependencies } - Map values = new HashMap(); - do { - boolean enable = matcher.group(1).equals("+"); - String name = matcher.group(2); - LanguageFeature feature = LanguageFeature.fromString(name); - if (feature == null) { - Assert.fail( - "Language feature not found, please check spelling: " + name + "\n" + - "Known features:\n " + StringsKt.join(Arrays.asList(LanguageFeature.values()), "\n ") - ); - } - if (values.put(feature, enable) != null) { - Assert.fail("Duplicate entry for the language feature: " + name); - } - } - while (matcher.find()); - - return values; - } - - private static Condition parseDiagnosticFilterDirective(Map directiveMap) { - String directives = directiveMap.get(DIAGNOSTICS_DIRECTIVE); - if (directives == null) { - // If "!API_VERSION" is present, disable the NEWER_VERSION_IN_SINCE_KOTLIN diagnostic. - // Otherwise it would be reported in any non-trivial test on the @SinceKotlin value. - if (directiveMap.containsKey(API_VERSION_DIRECTIVE)) { - return new Condition() { - @Override - public boolean value(Diagnostic diagnostic) { - return diagnostic.getFactory() != Errors.NEWER_VERSION_IN_SINCE_KOTLIN; - } - }; - } - return Conditions.alwaysTrue(); - } - Condition condition = Conditions.alwaysTrue(); - Matcher matcher = DIAGNOSTICS_PATTERN.matcher(directives); - if (!matcher.find()) { - Assert.fail("Wrong syntax in the '// !" + DIAGNOSTICS_DIRECTIVE + ": ...' directive:\n" + - "found: '" + directives + "'\n" + - "Must be '([+-!]DIAGNOSTIC_FACTORY_NAME|ERROR|WARNING|INFO)+'\n" + - "where '+' means 'include'\n" + - " '-' means 'exclude'\n" + - " '!' means 'exclude everything but this'\n" + - "directives are applied in the order of appearance, i.e. !FOO +BAR means include only FOO and BAR"); - } - boolean first = true; - do { - String operation = matcher.group(1); - final String name = matcher.group(2); - - Condition newCondition; - if (ImmutableSet.of("ERROR", "WARNING", "INFO").contains(name)) { - final Severity severity = Severity.valueOf(name); - newCondition = new Condition() { - @Override - public boolean value(Diagnostic diagnostic) { - return diagnostic.getSeverity() == severity; - } - }; - } - else { - newCondition = new Condition() { - @Override - public boolean value(Diagnostic diagnostic) { - return name.equals(diagnostic.getFactory().getName()); - } - }; - } - if ("!".equals(operation)) { - if (!first) { - Assert.fail("'" + operation + name + "' appears in a position rather than the first one, " + - "which effectively cancels all the previous filters in this directive"); - } - condition = newCondition; - } - else if ("+".equals(operation)) { - condition = Conditions.or(condition, newCondition); - } - else if ("-".equals(operation)) { - condition = Conditions.and(condition, Conditions.not(newCondition)); - } - first = false; - } - while (matcher.find()); - // We always include UNRESOLVED_REFERENCE and SYNTAX_ERROR because they are too likely to indicate erroneous test data - return Conditions.or( - condition, - new Condition() { - @Override - public boolean value(Diagnostic diagnostic) { - return DIAGNOSTICS_TO_INCLUDE_ANYWAY.contains(diagnostic.getFactory()); - } - }); - } - - protected static class TestModule implements Comparable { - private final String name; - private final List dependencies = new ArrayList(); - - public TestModule(@NotNull String name) { - this.name = name; + override fun compareTo(module: TestModule): Int { + return name.compareTo(module.name) } - @NotNull - public String getName() { - return name; - } - - @NotNull - public List getDependencies() { - return dependencies; - } - - @Override - public int compareTo(@NotNull TestModule module) { - return name.compareTo(module.getName()); - } - - @Override - public String toString() { - return getName(); + override fun toString(): String { + return name } } - public static class DiagnosticTestLanguageVersionSettings implements LanguageVersionSettings { - private final Map languageFeatures; - private final ApiVersion apiVersion; + class DiagnosticTestLanguageVersionSettings( + private val languageFeatures: Map, override val apiVersion: ApiVersion + ) : LanguageVersionSettings { - public DiagnosticTestLanguageVersionSettings( - @NotNull Map languageFeatures, @NotNull ApiVersion apiVersion - ) { - this.languageFeatures = languageFeatures; - this.apiVersion = apiVersion; + override fun supportsFeature(feature: LanguageFeature): Boolean { + val enabled = languageFeatures[feature] + return enabled ?: LanguageVersionSettingsImpl.DEFAULT.supportsFeature(feature) } - @Override - public boolean supportsFeature(@NotNull LanguageFeature feature) { - Boolean enabled = languageFeatures.get(feature); - return enabled != null ? enabled : LanguageVersionSettingsImpl.DEFAULT.supportsFeature(feature); - } + override // TODO provide base language version + val languageVersion: LanguageVersion + get() = throw UnsupportedOperationException("This instance of LanguageVersionSettings should be used for tests only") - @NotNull - @Override - public LanguageVersion getLanguageVersion() { - // TODO provide base language version - throw new UnsupportedOperationException("This instance of LanguageVersionSettings should be used for tests only"); - } - - @NotNull - @Override - public ApiVersion getApiVersion() { - return apiVersion; - } - - @Override - public boolean equals(Object obj) { - return obj instanceof DiagnosticTestLanguageVersionSettings && - ((DiagnosticTestLanguageVersionSettings) obj).languageFeatures.equals(languageFeatures) && - ((DiagnosticTestLanguageVersionSettings) obj).apiVersion.equals(apiVersion); + override fun equals(obj: Any?): Boolean { + return obj is DiagnosticTestLanguageVersionSettings && + obj.languageFeatures == languageFeatures && + obj.apiVersion == apiVersion } } - protected class TestFile { - private final List diagnosedRanges = Lists.newArrayList(); - public final String expectedText; - private final TestModule module; - private final String clearText; - private final KtFile jetFile; - private final Condition whatDiagnosticsToConsider; - public final LanguageVersionSettings customLanguageVersionSettings; - private final boolean declareCheckType; - private final boolean declareFlexibleType; - public final boolean checkLazyLog; - private final boolean markDynamicCalls; - private final List dynamicCallDescriptors = new ArrayList(); + inner class TestFile( + val module: TestModule?, + fileName: String, + textWithMarkers: String, + directives: Map + ) { + private val diagnosedRanges = Lists.newArrayList() + val expectedText: String + private val clearText: String + val jetFile: KtFile? + private val whatDiagnosticsToConsider: Condition + val customLanguageVersionSettings: LanguageVersionSettings + private val declareCheckType: Boolean + private val declareFlexibleType: Boolean + val checkLazyLog: Boolean + private val markDynamicCalls: Boolean + val dynamicCallDescriptors: List = ArrayList() - public TestFile( - @Nullable TestModule module, - String fileName, - String textWithMarkers, - Map directives - ) { - this.module = module; - this.whatDiagnosticsToConsider = parseDiagnosticFilterDirective(directives); - this.customLanguageVersionSettings = parseLanguageVersionSettings(directives); - this.checkLazyLog = directives.containsKey(CHECK_LAZY_LOG_DIRECTIVE) || CHECK_LAZY_LOG_DEFAULT; - this.declareCheckType = directives.containsKey(CHECK_TYPE_DIRECTIVE); - this.declareFlexibleType = directives.containsKey(EXPLICIT_FLEXIBLE_TYPES_DIRECTIVE); - this.markDynamicCalls = directives.containsKey(MARK_DYNAMIC_CALLS_DIRECTIVE); + init { + this.whatDiagnosticsToConsider = parseDiagnosticFilterDirective(directives) + this.customLanguageVersionSettings = parseLanguageVersionSettings(directives) + this.checkLazyLog = directives.containsKey(CHECK_LAZY_LOG_DIRECTIVE) || CHECK_LAZY_LOG_DEFAULT + this.declareCheckType = directives.containsKey(CHECK_TYPE_DIRECTIVE) + this.declareFlexibleType = directives.containsKey(EXPLICIT_FLEXIBLE_TYPES_DIRECTIVE) + this.markDynamicCalls = directives.containsKey(MARK_DYNAMIC_CALLS_DIRECTIVE) if (fileName.endsWith(".java")) { - PsiFileFactory.getInstance(getProject()).createFileFromText(fileName, JavaLanguage.INSTANCE, textWithMarkers); + PsiFileFactory.getInstance(project).createFileFromText(fileName, JavaLanguage.INSTANCE, textWithMarkers) // TODO: check there's not syntax errors - this.jetFile = null; - this.expectedText = this.clearText = textWithMarkers; + this.jetFile = null + this.clearText = textWithMarkers + this.expectedText = this.clearText } else { - this.expectedText = textWithMarkers; - String textWithExtras = addExtras(expectedText); - this.clearText = CheckerTestUtil.parseDiagnosedRanges(textWithExtras, diagnosedRanges); - this.jetFile = TestCheckerUtil.createCheckAndReturnPsiFile(fileName, clearText, getProject()); - for (CheckerTestUtil.DiagnosedRange diagnosedRange : diagnosedRanges) { - diagnosedRange.setFile(jetFile); + this.expectedText = textWithMarkers + val textWithExtras = addExtras(expectedText) + this.clearText = CheckerTestUtil.parseDiagnosedRanges(textWithExtras, diagnosedRanges) + this.jetFile = TestCheckerUtil.createCheckAndReturnPsiFile(fileName, clearText, project) + for (diagnosedRange in diagnosedRanges) { + diagnosedRange.file = jetFile } } } - @NotNull - private String getImports() { - String imports = ""; - if (declareCheckType) { - imports += CHECK_TYPE_IMPORT + "\n"; + private val imports: String + get() { + var imports = "" + if (declareCheckType) { + imports += CHECK_TYPE_IMPORT + "\n" + } + if (declareFlexibleType) { + imports += EXPLICIT_FLEXIBLE_TYPES_IMPORT + "\n" + } + return imports } - if (declareFlexibleType) { - imports += EXPLICIT_FLEXIBLE_TYPES_IMPORT + "\n"; - } - return imports; + + private val extras: String + get() = "/*extras*/\n$imports/*extras*/\n\n" + + private fun addExtras(text: String): String { + return addImports(text, extras) } - private String getExtras() { - return "/*extras*/\n" + getImports() + "/*extras*/\n\n"; - } - - private String addExtras(String text) { - return addImports(text, getExtras()); - } - - private void stripExtras(StringBuilder actualText) { - String extras = getExtras(); - int start = actualText.indexOf(extras); + private fun stripExtras(actualText: StringBuilder) { + val extras = extras + val start = actualText.indexOf(extras) if (start >= 0) { - actualText.delete(start, start + extras.length()); + actualText.delete(start, start + extras.length) } } - private String addImports(String text, String imports) { - Pattern pattern = Pattern.compile("^package [\\.\\w\\d]*\n", Pattern.MULTILINE); - Matcher matcher = pattern.matcher(text); + private fun addImports(text: String, imports: String): String { + var text = text + val pattern = Pattern.compile("^package [\\.\\w\\d]*\n", Pattern.MULTILINE) + val matcher = pattern.matcher(text) if (matcher.find()) { // add imports after the package directive - text = text.substring(0, matcher.end()) + imports + text.substring(matcher.end()); + text = text.substring(0, matcher.end()) + imports + text.substring(matcher.end()) } else { // add imports at the beginning - text = imports + text; + text = imports + text } - return text; + return text } - @Nullable - public TestModule getModule() { - return module; - } - - @Nullable - public KtFile getJetFile() { - return jetFile; - } - - @NotNull - public List getDynamicCallDescriptors() { - return dynamicCallDescriptors; - } - - public boolean getActualText(BindingContext bindingContext, StringBuilder actualText, boolean skipJvmSignatureDiagnostics) { + fun getActualText(bindingContext: BindingContext, actualText: StringBuilder, skipJvmSignatureDiagnostics: Boolean): Boolean { if (this.jetFile == null) { // TODO: check java files too - actualText.append(this.clearText); - return true; + actualText.append(this.clearText) + return true } - Set jvmSignatureDiagnostics = skipJvmSignatureDiagnostics - ? Collections.emptySet() - : computeJvmSignatureDiagnostics(bindingContext); + val jvmSignatureDiagnostics = if (skipJvmSignatureDiagnostics) + emptySet() + else + computeJvmSignatureDiagnostics(bindingContext) - final boolean[] ok = { true }; - List diagnostics = ContainerUtil.filter( - CollectionsKt.plus(CheckerTestUtil.getDiagnosticsIncludingSyntaxErrors(bindingContext, jetFile, markDynamicCalls, dynamicCallDescriptors), - jvmSignatureDiagnostics), + val ok = booleanArrayOf(true) + val diagnostics = ContainerUtil.filter( + CheckerTestUtil.getDiagnosticsIncludingSyntaxErrors(bindingContext, jetFile, markDynamicCalls, dynamicCallDescriptors).plus( + jvmSignatureDiagnostics), whatDiagnosticsToConsider - ); + ) - Map diagnosticToExpectedDiagnostic = ContainerUtil.newHashMap(); - CheckerTestUtil.diagnosticsDiff(diagnosticToExpectedDiagnostic, diagnosedRanges, diagnostics, new CheckerTestUtil.DiagnosticDiffCallbacks() { + val diagnosticToExpectedDiagnostic = ContainerUtil.newHashMap() + CheckerTestUtil.diagnosticsDiff(diagnosticToExpectedDiagnostic, diagnosedRanges, diagnostics, object : CheckerTestUtil.DiagnosticDiffCallbacks { - @Override - public void missingDiagnostic(CheckerTestUtil.TextDiagnostic diagnostic, int expectedStart, int expectedEnd) { - String message = "Missing " + diagnostic.getName() + DiagnosticUtils.atLocation(jetFile, new TextRange(expectedStart, expectedEnd)); - System.err.println(message); - ok[0] = false; + override fun missingDiagnostic(diagnostic: CheckerTestUtil.TextDiagnostic, expectedStart: Int, expectedEnd: Int) { + val message = "Missing " + diagnostic.name + DiagnosticUtils.atLocation(jetFile, TextRange(expectedStart, expectedEnd)) + System.err.println(message) + ok[0] = false } - @Override - public void wrongParametersDiagnostic( - CheckerTestUtil.TextDiagnostic expectedDiagnostic, - CheckerTestUtil.TextDiagnostic actualDiagnostic, - int start, - int end + override fun wrongParametersDiagnostic( + expectedDiagnostic: CheckerTestUtil.TextDiagnostic, + actualDiagnostic: CheckerTestUtil.TextDiagnostic, + start: Int, + end: Int ) { - String message = "Parameters of diagnostic not equal at position " - + DiagnosticUtils.atLocation(jetFile, new TextRange(start, end)) - + ". Expected: " + expectedDiagnostic.asString() + ", actual: " + actualDiagnostic.asString(); - System.err.println(message); - ok[0] = false; + val message = "Parameters of diagnostic not equal at position " + +DiagnosticUtils.atLocation(jetFile, TextRange(start, end)) + +". Expected: " + expectedDiagnostic.asString() + ", actual: " + actualDiagnostic.asString() + System.err.println(message) + ok[0] = false } - @Override - public void unexpectedDiagnostic(CheckerTestUtil.TextDiagnostic diagnostic, int actualStart, int actualEnd) { - String message = "Unexpected " + diagnostic.getName() + DiagnosticUtils.atLocation(jetFile, new TextRange(actualStart, actualEnd)); - System.err.println(message); - ok[0] = false; + override fun unexpectedDiagnostic(diagnostic: CheckerTestUtil.TextDiagnostic, actualStart: Int, actualEnd: Int) { + val message = "Unexpected " + diagnostic.name + DiagnosticUtils.atLocation(jetFile, TextRange(actualStart, actualEnd)) + System.err.println(message) + ok[0] = false } - }); + }) - actualText.append(CheckerTestUtil.addDiagnosticMarkersToText(jetFile, diagnostics, diagnosticToExpectedDiagnostic, new Function() { - @Override - public String fun(PsiFile file) { - return file.getText(); - } - })); + actualText.append(CheckerTestUtil.addDiagnosticMarkersToText(jetFile, diagnostics, diagnosticToExpectedDiagnostic, Function { file -> file.text })) - stripExtras(actualText); + stripExtras(actualText) - return ok[0]; + return ok[0] } - private Set computeJvmSignatureDiagnostics(BindingContext bindingContext) { - Set jvmSignatureDiagnostics = new HashSet(); - Collection declarations = PsiTreeUtil.findChildrenOfType(jetFile, KtDeclaration.class); - for (KtDeclaration declaration : declarations) { - Diagnostics diagnostics = DuplicateJvmSignatureUtilKt.getJvmSignatureDiagnostics(declaration, bindingContext.getDiagnostics(), - GlobalSearchScope.allScope(getProject())); - if (diagnostics == null) continue; - jvmSignatureDiagnostics.addAll(diagnostics.forElement(declaration)); + private fun computeJvmSignatureDiagnostics(bindingContext: BindingContext): Set { + val jvmSignatureDiagnostics = HashSet() + val declarations = PsiTreeUtil.findChildrenOfType(jetFile, KtDeclaration::class.java) + for (declaration in declarations) { + val diagnostics = getJvmSignatureDiagnostics(declaration, bindingContext.diagnostics, + GlobalSearchScope.allScope(project)) ?: continue + jvmSignatureDiagnostics.addAll(diagnostics.forElement(declaration)) } - return jvmSignatureDiagnostics; + return jvmSignatureDiagnostics } - @Override - public String toString() { - return jetFile.getName(); + override fun toString(): String { + return jetFile!!.name + } + } + + companion object { + + val DIAGNOSTICS_DIRECTIVE = "DIAGNOSTICS" + val DIAGNOSTICS_PATTERN = Pattern.compile("([\\+\\-!])(\\w+)\\s*") + val DIAGNOSTICS_TO_INCLUDE_ANYWAY: ImmutableSet> = ImmutableSet.of( + Errors.UNRESOLVED_REFERENCE, + Errors.UNRESOLVED_REFERENCE_WRONG_RECEIVER, + CheckerTestUtil.SyntaxErrorDiagnosticFactory.INSTANCE, + CheckerTestUtil.DebugInfoDiagnosticFactory.ELEMENT_WITH_ERROR_TYPE, + CheckerTestUtil.DebugInfoDiagnosticFactory.MISSING_UNRESOLVED, + CheckerTestUtil.DebugInfoDiagnosticFactory.UNRESOLVED_WITH_TARGET + ) + + val LANGUAGE_DIRECTIVE = "LANGUAGE" + private val LANGUAGE_PATTERN = Pattern.compile("([\\+\\-])(\\w+)\\s*") + + val API_VERSION_DIRECTIVE = "API_VERSION" + + val CHECK_TYPE_DIRECTIVE = "CHECK_TYPE" + val CHECK_TYPE_PACKAGE = "tests._checkType" + private val CHECK_TYPE_DECLARATIONS = "\npackage " + CHECK_TYPE_PACKAGE + + "\nfun checkSubtype(t: T) = t" + + "\nclass Inv" + + "\nfun Inv._() {}" + + "\ninfix fun T.checkType(f: Inv.() -> Unit) {}" + val CHECK_TYPE_IMPORT = "import $CHECK_TYPE_PACKAGE.*" + + val EXPLICIT_FLEXIBLE_TYPES_DIRECTIVE = "EXPLICIT_FLEXIBLE_TYPES" + val EXPLICIT_FLEXIBLE_PACKAGE = InternalFlexibleTypeTransformer.FLEXIBLE_TYPE_CLASSIFIER.packageFqName.asString() + val EXPLICIT_FLEXIBLE_CLASS_NAME = InternalFlexibleTypeTransformer.FLEXIBLE_TYPE_CLASSIFIER.relativeClassName.asString() + private val EXPLICIT_FLEXIBLE_TYPES_DECLARATIONS = "\npackage " + EXPLICIT_FLEXIBLE_PACKAGE + + "\npublic class " + EXPLICIT_FLEXIBLE_CLASS_NAME + "" + private val EXPLICIT_FLEXIBLE_TYPES_IMPORT = "import $EXPLICIT_FLEXIBLE_PACKAGE.$EXPLICIT_FLEXIBLE_CLASS_NAME" + val CHECK_LAZY_LOG_DIRECTIVE = "CHECK_LAZY_LOG" + val CHECK_LAZY_LOG_DEFAULT = "true" == System.getProperty("check.lazy.logs", "false") + + val MARK_DYNAMIC_CALLS_DIRECTIVE = "MARK_DYNAMIC_CALLS" + + private fun parseLanguageVersionSettings(directiveMap: Map): LanguageVersionSettings? { + val apiVersionString = directiveMap[API_VERSION_DIRECTIVE] + val directives = directiveMap[LANGUAGE_DIRECTIVE] + if (apiVersionString == null && directives == null) return null + + val apiVersion = (if (apiVersionString != null) ApiVersion.parse(apiVersionString) else ApiVersion.LATEST) ?: error("Unknown API version: " + apiVersionString!!) + + val languageFeatures = if (directives == null) emptyMap() else collectLanguageFeatureMap(directives) + + return DiagnosticTestLanguageVersionSettings(languageFeatures, apiVersion) + } + + private fun collectLanguageFeatureMap(directives: String): Map { + val matcher = LANGUAGE_PATTERN.matcher(directives) + if (!matcher.find()) { + Assert.fail( + "Wrong syntax in the '// !" + LANGUAGE_DIRECTIVE + ": ...' directive:\n" + + "found: '" + directives + "'\n" + + "Must be '([+-]LanguageFeatureName)+'\n" + + "where '+' means 'enable' and '-' means 'disable'\n" + + "and language feature names are names of enum entries in LanguageFeature enum class" + ) + } + + val values = HashMap() + do { + val enable = matcher.group(1) == "+" + val name = matcher.group(2) + val feature = LanguageFeature.fromString(name) + if (feature == null) { + Assert.fail( + "Language feature not found, please check spelling: " + name + "\n" + + "Known features:\n " + join(Arrays.asList(*LanguageFeature.values()), "\n ") + ) + } + if (values.put(feature, enable) != null) { + Assert.fail("Duplicate entry for the language feature: " + name) + } + } + while (matcher.find()) + + return values + } + + private fun parseDiagnosticFilterDirective(directiveMap: Map): Condition { + val directives = directiveMap[DIAGNOSTICS_DIRECTIVE] + if (directives == null) { + // If "!API_VERSION" is present, disable the NEWER_VERSION_IN_SINCE_KOTLIN diagnostic. + // Otherwise it would be reported in any non-trivial test on the @SinceKotlin value. + if (directiveMap.containsKey(API_VERSION_DIRECTIVE)) { + return Condition { diagnostic -> diagnostic.factory !== Errors.NEWER_VERSION_IN_SINCE_KOTLIN } + } + return Conditions.alwaysTrue() + } + var condition = Conditions.alwaysTrue() + val matcher = DIAGNOSTICS_PATTERN.matcher(directives) + if (!matcher.find()) { + Assert.fail("Wrong syntax in the '// !" + DIAGNOSTICS_DIRECTIVE + ": ...' directive:\n" + + "found: '" + directives + "'\n" + + "Must be '([+-!]DIAGNOSTIC_FACTORY_NAME|ERROR|WARNING|INFO)+'\n" + + "where '+' means 'include'\n" + + " '-' means 'exclude'\n" + + " '!' means 'exclude everything but this'\n" + + "directives are applied in the order of appearance, i.e. !FOO +BAR means include only FOO and BAR") + } + var first = true + do { + val operation = matcher.group(1) + val name = matcher.group(2) + + var newCondition: Condition + if (ImmutableSet.of("ERROR", "WARNING", "INFO").contains(name)) { + val severity = Severity.valueOf(name) + newCondition = Condition { diagnostic -> diagnostic.severity == severity } + } + else { + newCondition = Condition { diagnostic -> name == diagnostic.factory.name } + } + if ("!" == operation) { + if (!first) { + Assert.fail("'" + operation + name + "' appears in a position rather than the first one, " + + "which effectively cancels all the previous filters in this directive") + } + condition = newCondition + } + else if ("+" == operation) { + condition = Conditions.or(condition, newCondition) + } + else if ("-" == operation) { + condition = Conditions.and(condition, Conditions.not(newCondition)) + } + first = false + } + while (matcher.find()) + // We always include UNRESOLVED_REFERENCE and SYNTAX_ERROR because they are too likely to indicate erroneous test data + return Conditions.or( + condition, + Condition { diagnostic -> DIAGNOSTICS_TO_INCLUDE_ANYWAY.contains(diagnostic.factory) }) } } } diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/AbstractDiagnosticsTestWithJsStdLib.kt b/compiler/tests/org/jetbrains/kotlin/checkers/AbstractDiagnosticsTestWithJsStdLib.kt index 19064468ef9..783d712eec9 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/AbstractDiagnosticsTestWithJsStdLib.kt +++ b/compiler/tests/org/jetbrains/kotlin/checkers/AbstractDiagnosticsTestWithJsStdLib.kt @@ -14,134 +14,115 @@ * limitations under the License. */ -package org.jetbrains.kotlin.checkers; +package org.jetbrains.kotlin.checkers -import com.intellij.openapi.util.text.StringUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles; -import org.jetbrains.kotlin.config.CommonConfigurationKeys; -import org.jetbrains.kotlin.config.CompilerConfiguration; -import org.jetbrains.kotlin.config.LanguageVersionSettings; -import org.jetbrains.kotlin.context.ModuleContext; -import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl; -import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS; -import org.jetbrains.kotlin.js.analyzer.JsAnalysisResult; -import org.jetbrains.kotlin.js.config.JSConfigurationKeys; -import org.jetbrains.kotlin.js.config.JsConfig; -import org.jetbrains.kotlin.js.config.LibrarySourcesConfig; -import org.jetbrains.kotlin.js.resolve.BindingContextSlicesJsKt; -import org.jetbrains.kotlin.js.resolve.JsPlatform; -import org.jetbrains.kotlin.name.Name; -import org.jetbrains.kotlin.psi.KtFile; -import org.jetbrains.kotlin.resolve.BindingTrace; -import org.jetbrains.kotlin.serialization.js.JsModuleDescriptor; -import org.jetbrains.kotlin.serialization.js.ModuleKind; -import org.jetbrains.kotlin.storage.StorageManager; -import org.jetbrains.kotlin.test.KotlinTestUtils; +import com.intellij.openapi.util.text.StringUtil +import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles +import org.jetbrains.kotlin.config.CommonConfigurationKeys +import org.jetbrains.kotlin.config.CompilerConfiguration +import org.jetbrains.kotlin.config.LanguageVersionSettings +import org.jetbrains.kotlin.context.ModuleContext +import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl +import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS +import org.jetbrains.kotlin.js.analyzer.JsAnalysisResult +import org.jetbrains.kotlin.js.config.JSConfigurationKeys +import org.jetbrains.kotlin.js.config.JsConfig +import org.jetbrains.kotlin.js.config.LibrarySourcesConfig +import org.jetbrains.kotlin.js.resolve.* +import org.jetbrains.kotlin.js.resolve.JsPlatform +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.resolve.BindingTrace +import org.jetbrains.kotlin.serialization.js.JsModuleDescriptor +import org.jetbrains.kotlin.serialization.js.ModuleKind +import org.jetbrains.kotlin.storage.StorageManager +import org.jetbrains.kotlin.test.KotlinTestUtils -import java.util.ArrayList; -import java.util.List; -import java.util.Map; +import java.util.ArrayList -public abstract class AbstractDiagnosticsTestWithJsStdLib extends AbstractDiagnosticsTest { - private JsConfig config; +abstract class AbstractDiagnosticsTestWithJsStdLib : AbstractDiagnosticsTest() { + protected var config: JsConfig? = null + private set - @Override - protected void setUp() throws Exception { - super.setUp(); - CompilerConfiguration configuration = getEnvironment().getConfiguration().copy(); - configuration.put(CommonConfigurationKeys.MODULE_NAME, KotlinTestUtils.TEST_MODULE_NAME); - configuration.put(JSConfigurationKeys.LIBRARY_FILES, LibrarySourcesConfig.JS_STDLIB); - config = new LibrarySourcesConfig(getProject(), configuration); + @Throws(Exception::class) + override fun setUp() { + super.setUp() + val configuration = environment.configuration.copy() + configuration.put(CommonConfigurationKeys.MODULE_NAME, KotlinTestUtils.TEST_MODULE_NAME) + configuration.put(JSConfigurationKeys.LIBRARY_FILES, LibrarySourcesConfig.JS_STDLIB) + config = LibrarySourcesConfig(project, configuration) } - @Override - protected void tearDown() throws Exception { - config = null; - super.tearDown(); + @Throws(Exception::class) + override fun tearDown() { + config = null + super.tearDown() } - @Override - @NotNull - protected List getEnvironmentConfigFiles() { - return EnvironmentConfigFiles.JS_CONFIG_FILES; + override fun getEnvironmentConfigFiles(): List { + return EnvironmentConfigFiles.JS_CONFIG_FILES } - @Override - @NotNull - protected JsAnalysisResult analyzeModuleContents( - @NotNull ModuleContext moduleContext, - @NotNull List ktFiles, - @NotNull BindingTrace moduleTrace, - @Nullable LanguageVersionSettings languageVersionSettings, - boolean separateModules - ) { + override fun analyzeModuleContents( + moduleContext: ModuleContext, + ktFiles: List, + moduleTrace: BindingTrace, + languageVersionSettings: LanguageVersionSettings?, + separateModules: Boolean + ): JsAnalysisResult { // TODO: support LANGUAGE directive in JS diagnostic tests - assert languageVersionSettings == null - : BaseDiagnosticsTest.LANGUAGE_DIRECTIVE + " directive is not supported in JS diagnostic tests"; - moduleTrace.record(BindingContextSlicesJsKt.MODULE_KIND, moduleContext.getModule(), getModuleKind(ktFiles)); - return TopDownAnalyzerFacadeForJS.analyzeFilesWithGivenTrace(ktFiles, moduleTrace, moduleContext, config); + assert(languageVersionSettings == null) { BaseDiagnosticsTest.LANGUAGE_DIRECTIVE + " directive is not supported in JS diagnostic tests" } + moduleTrace.record(MODULE_KIND, moduleContext.module, getModuleKind(ktFiles)) + return TopDownAnalyzerFacadeForJS.analyzeFilesWithGivenTrace(ktFiles, moduleTrace, moduleContext, config!!) } - @NotNull - private static ModuleKind getModuleKind(@NotNull List ktFiles) { - ModuleKind kind = ModuleKind.PLAIN; - for (KtFile file : ktFiles) { - String text = file.getText(); - for (String line : StringUtil.splitByLines(text)) { - line = line.trim(); - if (!line.startsWith("//")) continue; - line = line.substring(2).trim(); - List parts = StringUtil.split(line, ":"); - if (parts.size() != 2) continue; + private fun getModuleKind(ktFiles: List): ModuleKind { + var kind = ModuleKind.PLAIN + for (file in ktFiles) { + val text = file.text + for (line in StringUtil.splitByLines(text)) { + line = line.trim { it <= ' ' } + if (!line.startsWith("//")) continue + line = line.substring(2).trim { it <= ' ' } + val parts = StringUtil.split(line, ":") + if (parts.size != 2) continue - if (!parts.get(0).trim().equals("MODULE_KIND")) continue; - kind = ModuleKind.valueOf(parts.get(1).trim()); + if (parts[0].trim { it <= ' ' } != "MODULE_KIND") continue + kind = ModuleKind.valueOf(parts[1].trim { it <= ' ' }) } } - return kind; + return kind } - @Override - @NotNull - protected List getAdditionalDependencies(@NotNull ModuleDescriptorImpl module) { - List dependencies = new ArrayList(); - for (JsModuleDescriptor moduleDescriptor : config.getModuleDescriptors()) { - dependencies.add(moduleDescriptor.getData()); + override fun getAdditionalDependencies(module: ModuleDescriptorImpl): List { + val dependencies = ArrayList() + for (moduleDescriptor in config!!.moduleDescriptors) { + dependencies.add(moduleDescriptor.data) } - return dependencies; + return dependencies } - @Override - public boolean shouldSkipJvmSignatureDiagnostics(Map> groupedByModule) { - return true; + override fun shouldSkipJvmSignatureDiagnostics(groupedByModule: Map>): Boolean { + return true } - @NotNull - @Override - protected ModuleDescriptorImpl createModule(@NotNull String moduleName, @NotNull StorageManager storageManager) { - return new ModuleDescriptorImpl(Name.special("<" + moduleName + ">"), storageManager, JsPlatform.INSTANCE.getBuiltIns()); + override fun createModule(moduleName: String, storageManager: StorageManager): ModuleDescriptorImpl { + return ModuleDescriptorImpl(Name.special("<$moduleName>"), storageManager, JsPlatform.builtIns) } - @NotNull - @Override - protected ModuleDescriptorImpl createSealedModule(@NotNull StorageManager storageManager) { - ModuleDescriptorImpl module = createModule("kotlin-js-test-module", storageManager); + override fun createSealedModule(storageManager: StorageManager): ModuleDescriptorImpl { + val module = createModule("kotlin-js-test-module", storageManager) - List dependencies = new ArrayList(); - dependencies.add(module); + val dependencies = ArrayList() + dependencies.add(module) - dependencies.addAll(getAdditionalDependencies(module)); + dependencies.addAll(getAdditionalDependencies(module)) - dependencies.add(module.getBuiltIns().getBuiltInsModule()); - module.setDependencies(dependencies); + dependencies.add(module.builtIns.builtInsModule) + module.setDependencies(dependencies) - return module; - } - - protected JsConfig getConfig() { - return config; + return module } }