Introduce "-api-version" CLI option

The `@SinceKotlin("X.Y.Z")` annotation now hides a particular declaration from
resolution when the API version specified by the `-api-version` option is
_less_ than X.Y.Z. The comparison is performed as for versions in Maven:
MavenComparableVersion is in fact a copy of
org.apache.maven.artifact.versioning.ComparableVersion.

Also support "!API_VERSION" directive in diagnostic tests

 #KT-14298 Fixed
This commit is contained in:
Alexander Udalov
2016-09-26 19:56:22 +03:00
parent e3df8ed2fe
commit 167ab1f860
59 changed files with 1758 additions and 57 deletions
@@ -34,6 +34,7 @@ import kotlin.jvm.functions.Function1;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.asJava.DuplicateJvmSignatureUtilKt;
import org.jetbrains.kotlin.config.ApiVersion;
import org.jetbrains.kotlin.config.LanguageFeature;
import org.jetbrains.kotlin.config.LanguageVersionSettings;
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl;
@@ -71,6 +72,8 @@ public abstract class BaseDiagnosticsTest
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 +
@@ -155,14 +158,26 @@ public abstract class BaseDiagnosticsTest
}
@Nullable
private static LanguageVersionSettings parseLanguageDirective(Map<String, String> directiveMap) {
private static LanguageVersionSettings parseLanguageVersionSettings(Map<String, String> directiveMap) {
String apiVersionString = directiveMap.get(API_VERSION_DIRECTIVE);
String directives = directiveMap.get(LANGUAGE_DIRECTIVE);
if (directives == null) return null;
if (apiVersionString == null && directives == null) return null;
ApiVersion apiVersion = apiVersionString != null ? ApiVersion.Companion.parse(apiVersionString) : ApiVersion.LATEST;
assert apiVersion != null : "Unknown API version: " + apiVersionString;
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:\n" +
"Wrong syntax in the '// !" + LANGUAGE_DIRECTIVE + ": ...' directive:\n" +
"found: '" + directives + "'\n" +
"Must be '([+-]LanguageFeatureName)+'\n" +
"where '+' means 'enable' and '-' means 'disable'\n" +
@@ -170,7 +185,7 @@ public abstract class BaseDiagnosticsTest
);
}
final Map<LanguageFeature, Boolean> values = new HashMap<LanguageFeature, Boolean>();
Map<LanguageFeature, Boolean> values = new HashMap<LanguageFeature, Boolean>();
do {
boolean enable = matcher.group(1).equals("+");
String name = matcher.group(2);
@@ -187,16 +202,7 @@ public abstract class BaseDiagnosticsTest
}
while (matcher.find());
return new LanguageVersionSettings() {
@Override
public boolean supportsFeature(@NotNull LanguageFeature feature) {
Boolean enabled = values.get(feature);
if (enabled != null) {
return enabled;
}
return LanguageVersionSettingsImpl.DEFAULT.supportsFeature(feature);
}
};
return values;
}
public static Condition<Diagnostic> parseDiagnosticFilterDirective(Map<String, String> directiveMap) {
@@ -207,7 +213,7 @@ public abstract class BaseDiagnosticsTest
Condition<Diagnostic> condition = Conditions.alwaysTrue();
Matcher matcher = DIAGNOSTICS_PATTERN.matcher(directives);
if (!matcher.find()) {
Assert.fail("Wrong syntax in the '// !DIAGNOSTICS: ...' directive:\n" +
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" +
@@ -289,6 +295,37 @@ public abstract class BaseDiagnosticsTest
}
}
public static class DiagnosticTestLanguageVersionSettings implements LanguageVersionSettings {
private final Map<LanguageFeature, Boolean> languageFeatures;
private final ApiVersion apiVersion;
public DiagnosticTestLanguageVersionSettings(
@NotNull Map<LanguageFeature, Boolean> languageFeatures, @NotNull ApiVersion apiVersion
) {
this.languageFeatures = languageFeatures;
this.apiVersion = apiVersion;
}
@Override
public boolean supportsFeature(@NotNull LanguageFeature feature) {
Boolean enabled = languageFeatures.get(feature);
return enabled != null ? enabled : LanguageVersionSettingsImpl.DEFAULT.supportsFeature(feature);
}
@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 {
private final List<CheckerTestUtil.DiagnosedRange> diagnosedRanges = Lists.newArrayList();
public final String expectedText;
@@ -311,7 +348,7 @@ public abstract class BaseDiagnosticsTest
) {
this.module = module;
this.whatDiagnosticsToConsider = parseDiagnosticFilterDirective(directives);
this.customLanguageVersionSettings = parseLanguageDirective(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);