Render platform name in multiplatform diagnostic tests

Prepend the platform name to the diagnostic in a common module, which is
reported when sources of that common module are analyzed as a part of the
platform source set: "<!JVM:...!> ... <!>". Fix some existing tests, mostly by
adding "impl" to implementations
This commit is contained in:
Alexander Udalov
2016-12-21 12:24:06 +03:00
parent e4d85ac527
commit 5556c59fc9
15 changed files with 170 additions and 75 deletions
@@ -34,6 +34,7 @@ import kotlin.Pair;
import kotlin.TuplesKt;
import kotlin.collections.CollectionsKt;
import kotlin.jvm.functions.Function1;
import kotlin.text.StringsKt;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
@@ -48,6 +49,7 @@ import org.jetbrains.kotlin.psi.KtExpression;
import org.jetbrains.kotlin.psi.KtReferenceExpression;
import org.jetbrains.kotlin.resolve.AnalyzingUtils;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.MultiTargetPlatform;
import org.jetbrains.kotlin.util.slicedMap.WritableSlice;
import java.util.*;
@@ -84,7 +86,7 @@ public class CheckerTestUtil {
private static final String IGNORE_DIAGNOSTIC_PARAMETER = "IGNORE";
private static final String SHOULD_BE_ESCAPED = "\\)\\(;";
private static final String DIAGNOSTIC_PARAMETER = "(?:(?:\\\\[" + SHOULD_BE_ESCAPED + "])|[^" + SHOULD_BE_ESCAPED + "])+";
private static final String INDIVIDUAL_DIAGNOSTIC = "(\\w+)(\\(" + DIAGNOSTIC_PARAMETER + "(;\\s*" + DIAGNOSTIC_PARAMETER + ")*\\))?";
private static final String INDIVIDUAL_DIAGNOSTIC = "(\\w+:)?(\\w+)(\\(" + DIAGNOSTIC_PARAMETER + "(;\\s*" + DIAGNOSTIC_PARAMETER + ")*\\))?";
private static final Pattern RANGE_START_OR_END_PATTERN = Pattern.compile("(<!" +
INDIVIDUAL_DIAGNOSTIC + "(,\\s*" +
INDIVIDUAL_DIAGNOSTIC + ")*!>)|(<!>)");
@@ -94,23 +96,57 @@ public class CheckerTestUtil {
@NotNull
public static List<ActualDiagnostic> getDiagnosticsIncludingSyntaxErrors(
@NotNull BindingContext bindingContext,
@NotNull List<Pair<MultiTargetPlatform, BindingContext>> implementingModulesBindings,
@NotNull PsiElement root,
boolean markDynamicCalls,
@Nullable List<DeclarationDescriptor> dynamicCallDescriptors
) {
List<ActualDiagnostic> result =
getDiagnosticsIncludingSyntaxErrors(bindingContext, root, markDynamicCalls, dynamicCallDescriptors, null);
List<Pair<MultiTargetPlatform, BindingContext>> sortedBindings = CollectionsKt.sortedWith(
implementingModulesBindings,
new Comparator<Pair<MultiTargetPlatform, BindingContext>>() {
@Override
public int compare(Pair<MultiTargetPlatform, BindingContext> o1, Pair<MultiTargetPlatform, BindingContext> o2) {
return o1.getFirst().compareTo(o2.getFirst());
}
}
);
for (Pair<MultiTargetPlatform, BindingContext> binding : sortedBindings) {
MultiTargetPlatform platform = binding.getFirst();
assert platform instanceof MultiTargetPlatform.Specific : "Implementing module must have a specific platform: " + platform;
result.addAll(getDiagnosticsIncludingSyntaxErrors(
binding.getSecond(), root, markDynamicCalls, dynamicCallDescriptors,
((MultiTargetPlatform.Specific) platform).getPlatform()
));
}
return result;
}
@NotNull
public static List<ActualDiagnostic> getDiagnosticsIncludingSyntaxErrors(
@NotNull BindingContext bindingContext,
@NotNull PsiElement root,
boolean markDynamicCalls,
@Nullable List<DeclarationDescriptor> dynamicCallDescriptors,
@Nullable String platform
) {
List<ActualDiagnostic> diagnostics = new ArrayList<ActualDiagnostic>();
for (Diagnostic diagnostic : bindingContext.getDiagnostics().all()) {
if (PsiTreeUtil.isAncestor(root, diagnostic.getPsiElement(), false)) {
diagnostics.add(new ActualDiagnostic(diagnostic));
diagnostics.add(new ActualDiagnostic(diagnostic, platform));
}
}
for (PsiErrorElement errorElement : AnalyzingUtils.getSyntaxErrorRanges(root)) {
diagnostics.add(new ActualDiagnostic(new SyntaxErrorDiagnostic(errorElement)));
diagnostics.add(new ActualDiagnostic(new SyntaxErrorDiagnostic(errorElement), platform));
}
List<ActualDiagnostic> debugAnnotations = getDebugInfoDiagnostics(root, bindingContext, markDynamicCalls, dynamicCallDescriptors);
diagnostics.addAll(debugAnnotations);
diagnostics.addAll(getDebugInfoDiagnostics(root, bindingContext, markDynamicCalls, dynamicCallDescriptors, platform));
return diagnostics;
}
@@ -120,7 +156,8 @@ public class CheckerTestUtil {
@NotNull PsiElement root,
@NotNull BindingContext bindingContext,
final boolean markDynamicCalls,
@Nullable final List<DeclarationDescriptor> dynamicCallDescriptors
@Nullable final List<DeclarationDescriptor> dynamicCallDescriptors,
@Nullable final String platform
) {
final List<ActualDiagnostic> debugAnnotations = new ArrayList<ActualDiagnostic>();
@@ -152,7 +189,7 @@ public class CheckerTestUtil {
}
private void newDiagnostic(KtElement element, DebugInfoDiagnosticFactory factory) {
debugAnnotations.add(new ActualDiagnostic(new DebugInfoDiagnostic(element, factory)));
debugAnnotations.add(new ActualDiagnostic(new DebugInfoDiagnostic(element, factory), platform));
}
});
@@ -167,7 +204,7 @@ public class CheckerTestUtil {
)) {
for (KtExpression expression : bindingContext.getSliceContents(factory.getFirst()).keySet()) {
if (PsiTreeUtil.isAncestor(root, expression, false)) {
debugAnnotations.add(new ActualDiagnostic(new DebugInfoDiagnostic(expression, factory.getSecond())));
debugAnnotations.add(new ActualDiagnostic(new DebugInfoDiagnostic(expression, factory.getSecond()), platform));
}
}
}
@@ -267,7 +304,7 @@ public class CheckerTestUtil {
actualDiagnostics.entrySet(), new Function1<Map.Entry<ActualDiagnostic, TextDiagnostic>, Boolean>() {
@Override
public Boolean invoke(Map.Entry<ActualDiagnostic, TextDiagnostic> entry) {
return expectedDiagnostic.getName().equals(entry.getValue().getName());
return expectedDiagnostic.getDescription().equals(entry.getValue().getDescription());
}
}
);
@@ -294,7 +331,7 @@ public class CheckerTestUtil {
}
private static boolean compareTextDiagnostic(@NotNull TextDiagnostic expected, @NotNull TextDiagnostic actual) {
if (!expected.getName().equals(actual.getName())) return false;
if (!expected.getDescription().equals(actual.getDescription())) return false;
if (expected.getParameters() == null) return true;
if (actual.getParameters() == null || expected.getParameters().size() != actual.getParameters().size()) return false;
@@ -461,6 +498,10 @@ public class CheckerTestUtil {
}
}
else {
if (diagnostic.platform != null) {
result.append(diagnostic.platform);
result.append(":");
}
result.append(diagnostic.getName());
}
if (iterator.hasNext()) {
@@ -633,9 +674,11 @@ public class CheckerTestUtil {
public static class ActualDiagnostic {
public final Diagnostic diagnostic;
public final String platform;
ActualDiagnostic(@NotNull Diagnostic diagnostic) {
ActualDiagnostic(@NotNull Diagnostic diagnostic, @Nullable String platform) {
this.diagnostic = diagnostic;
this.platform = platform;
}
@NotNull
@@ -650,18 +693,22 @@ public class CheckerTestUtil {
@Override
public boolean equals(Object obj) {
if (!(obj instanceof ActualDiagnostic)) return false;
ActualDiagnostic other = (ActualDiagnostic) obj;
// '==' on diagnostics is intentional here
return obj instanceof ActualDiagnostic && ((ActualDiagnostic) obj).diagnostic == diagnostic;
return other.diagnostic == diagnostic &&
(other.platform == null ? platform == null : other.platform.equals(platform));
}
@Override
public int hashCode() {
return System.identityHashCode(diagnostic);
return System.identityHashCode(diagnostic) * 31 + (platform != null ? platform.hashCode() : 0);
}
@Override
public String toString() {
return diagnostic.toString();
return (platform != null ? platform + ":" : "") + diagnostic.toString();
}
}
@@ -671,18 +718,22 @@ public class CheckerTestUtil {
Matcher matcher = INDIVIDUAL_DIAGNOSTIC_PATTERN.matcher(text);
if (!matcher.find())
throw new IllegalArgumentException("Could not parse diagnostic: " + text);
String name = matcher.group(1);
String parameters = matcher.group(2);
String platformPrefix = matcher.group(1);
assert platformPrefix == null || platformPrefix.endsWith(":") : platformPrefix;
String platform = platformPrefix == null ? null : StringsKt.substringBeforeLast(platformPrefix, ":", platformPrefix);
String name = matcher.group(2);
String parameters = matcher.group(3);
if (parameters == null) {
return new TextDiagnostic(name, null);
return new TextDiagnostic(name, platform, null);
}
List<String> parsedParameters = new SmartList<String>();
Matcher parametersMatcher = INDIVIDUAL_PARAMETER_PATTERN.matcher(parameters);
while (parametersMatcher.find())
parsedParameters.add(unescape(parametersMatcher.group().trim()));
return new TextDiagnostic(name, parsedParameters);
return new TextDiagnostic(name, platform, parsedParameters);
}
private static @NotNull String escape(@NotNull String s) {
@@ -708,24 +759,32 @@ public class CheckerTestUtil {
return o != null ? o.toString() : "null";
}
});
return new TextDiagnostic(diagnosticName, parameters);
return new TextDiagnostic(diagnosticName, actualDiagnostic.platform, parameters);
}
return new TextDiagnostic(diagnosticName, null);
return new TextDiagnostic(diagnosticName, actualDiagnostic.platform, null);
}
@NotNull
private final String name;
@Nullable
private final String platform;
@Nullable
private final List<String> parameters;
public TextDiagnostic(@NotNull String name, @Nullable List<String> parameters) {
public TextDiagnostic(@NotNull String name, @Nullable String platform, @Nullable List<String> parameters) {
this.name = name;
this.platform = platform;
this.parameters = parameters;
}
@Nullable
public String getPlatform() {
return platform;
}
@NotNull
public String getName() {
return name;
public String getDescription() {
return (platform != null ? platform + ":" : "") + name;
}
@Nullable
@@ -741,6 +800,7 @@ public class CheckerTestUtil {
TextDiagnostic that = (TextDiagnostic) o;
if (!name.equals(that.name)) return false;
if (platform != null ? !platform.equals(that.platform) : that.platform != null) return false;
if (parameters != null ? !parameters.equals(that.parameters) : that.parameters != null) return false;
return true;
@@ -749,20 +809,30 @@ public class CheckerTestUtil {
@Override
public int hashCode() {
int result = name.hashCode();
result = 31 * result + (platform != null ? platform.hashCode() : 0);
result = 31 * result + (parameters != null ? parameters.hashCode() : 0);
return result;
}
@NotNull
public String asString() {
if (parameters == null)
return name;
return name + '(' + StringUtil.join(parameters, new Function<String, String>() {
@Override
public String fun(String s) {
return escape(s);
}
}, "; ") + ')';
StringBuilder result = new StringBuilder();
if (platform != null) {
result.append(platform);
result.append(":");
}
result.append(name);
if (parameters != null) {
result.append("(");
result.append(StringUtil.join(parameters, new Function<String, String>() {
@Override
public String fun(String s) {
return escape(s);
}
}, "; "));
result.append(")");
}
return result.toString();
}
@Override
@@ -20,10 +20,19 @@ import org.jetbrains.kotlin.descriptors.MemberDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.resolve.descriptorUtil.module
sealed class MultiTargetPlatform {
object Common : MultiTargetPlatform()
sealed class MultiTargetPlatform : Comparable<MultiTargetPlatform> {
object Common : MultiTargetPlatform() {
override fun compareTo(other: MultiTargetPlatform): Int =
if (other is Common) 0 else -1
}
data class Specific(val platform: String) : MultiTargetPlatform()
data class Specific(val platform: String) : MultiTargetPlatform() {
override fun compareTo(other: MultiTargetPlatform): Int =
when (other) {
is Common -> 1
is Specific -> platform.compareTo(other.platform)
}
}
companion object {
@JvmField