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