[TEST] Extract compiler-specific test utils from :tests-common to new module

This commit is contained in:
Dmitriy Novozhilov
2020-12-14 15:20:28 +03:00
parent d15c7861b2
commit 1fe5148f0d
43 changed files with 412 additions and 199 deletions
@@ -0,0 +1,55 @@
plugins {
kotlin("jvm")
id("jps-compatible")
}
dependencies {
testCompile(kotlinStdlib("jdk8"))
testCompile(project(":kotlin-scripting-compiler"))
testCompile(project(":core:descriptors"))
testCompile(project(":core:descriptors.jvm"))
testCompile(project(":core:deserialization"))
testCompile(project(":compiler:util"))
testCompile(project(":compiler:tests-mutes"))
testCompile(project(":compiler:backend"))
testCompile(project(":compiler:ir.ir2cfg"))
testCompile(project(":compiler:frontend"))
testCompile(project(":compiler:frontend.java"))
testCompile(project(":compiler:util"))
testCompile(project(":compiler:psi"))
testCompile(project(":compiler:cli-common"))
testCompile(project(":compiler:cli"))
testCompile(project(":compiler:cli-js"))
testCompile(project(":compiler:serialization"))
testCompile(projectTests(":compiler:test-infrastructure-utils"))
testCompileOnly(intellijCoreDep()) { includeJars("intellij-core") }
testCompile(intellijDep()) {
includeJars(
"jps-model",
"extensions",
"util",
"platform-api",
"platform-impl",
"idea",
"idea_rt",
"guava",
"trove4j",
"asm-all",
"log4j",
"jdom",
"streamex",
"bootstrap",
rootProject = rootProject
)
isTransitive = false
}
}
sourceSets {
"main" { none() }
"test" { projectDefault() }
}
testsJar {}
@@ -0,0 +1,67 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir
import org.jetbrains.kotlin.fir.references.FirControlFlowGraphReference
import org.jetbrains.kotlin.fir.resolve.dfa.FirControlFlowGraphReferenceImpl
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.CFGNode
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.ControlFlowGraph
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.EdgeKind
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
import org.jetbrains.kotlin.test.Assertions
class FirCfgConsistencyChecker(private val assertions: Assertions) : FirVisitorVoid() {
override fun visitElement(element: FirElement) {
element.acceptChildren(this)
}
override fun visitControlFlowGraphReference(controlFlowGraphReference: FirControlFlowGraphReference) {
val graph = (controlFlowGraphReference as? FirControlFlowGraphReferenceImpl)?.controlFlowGraph ?: return
assertions.assertEquals(ControlFlowGraph.State.Completed, graph.state)
checkConsistency(graph)
checkOrder(graph)
}
private fun checkConsistency(graph: ControlFlowGraph) {
for (node in graph.nodes) {
for (to in node.followingNodes) {
checkEdge(node, to)
}
for (from in node.previousNodes) {
checkEdge(from, node)
}
if (node.followingNodes.isEmpty() && node.previousNodes.isEmpty()) {
throw AssertionError("Unconnected CFG node: $node")
}
}
}
private val cfgKinds = listOf(EdgeKind.DeadForward, EdgeKind.CfgForward, EdgeKind.DeadBackward, EdgeKind.CfgBackward)
private fun checkEdge(from: CFGNode<*>, to: CFGNode<*>) {
assertions.assertContainsElements(from.followingNodes, to)
assertions.assertContainsElements(to.previousNodes, from)
val fromKind = from.outgoingEdges.getValue(to).kind
val toKind = to.incomingEdges.getValue(from).kind
assertions.assertEquals(fromKind, toKind)
if (from.isDead && to.isDead) {
assertions.assertContainsElements(cfgKinds, toKind)
}
}
private fun checkOrder(graph: ControlFlowGraph) {
val visited = mutableSetOf<CFGNode<*>>()
for (node in graph.nodes) {
for (previousNode in node.previousNodes) {
if (previousNode.owner != graph) continue
if (!node.incomingEdges.getValue(previousNode).kind.isBack) {
assertions.assertTrue(previousNode in visited)
}
}
visited += node
}
}
}
@@ -0,0 +1,54 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir
import org.jetbrains.kotlin.fir.types.*
fun ConeKotlinType.renderForDebugInfo(): String {
val nullabilitySuffix = if (this !is ConeKotlinErrorType && this !is ConeClassErrorType) nullability.suffix else ""
return when (this) {
is ConeTypeVariableType -> "TypeVariable(${this.lookupTag.name})"
is ConeDefinitelyNotNullType -> "${original.renderForDebugInfo()}!!"
is ConeClassErrorType -> "ERROR CLASS: ${diagnostic.reason}"
is ConeCapturedType -> "CapturedType(${constructor.projection.renderForDebugInfo()})"
is ConeClassLikeType -> {
buildString {
append(lookupTag.classId.asSingleFqName().asString())
if (typeArguments.isNotEmpty()) {
append(typeArguments.joinToString(prefix = "<", postfix = ">") {
it.renderForDebugInfo()
})
}
}
}
is ConeLookupTagBasedType -> {
lookupTag.name.asString()
}
is ConeFlexibleType -> {
buildString {
append(lowerBound.renderForDebugInfo())
append("..")
append(upperBound.renderForDebugInfo())
}
}
is ConeIntersectionType -> {
intersectedTypes.joinToString(
separator = " & ",
) { it.renderForDebugInfo() }
}
is ConeStubType -> "Stub: $variable"
is ConeIntegerLiteralType -> "ILT: $value"
} + nullabilitySuffix
}
private fun ConeTypeProjection.renderForDebugInfo(): String {
return when (this) {
ConeStarProjection -> "*"
is ConeKotlinTypeProjectionIn -> "in ${type.renderForDebugInfo()}"
is ConeKotlinTypeProjectionOut -> "out ${type.renderForDebugInfo()}"
is ConeKotlinType -> renderForDebugInfo()
}
}
@@ -0,0 +1,123 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.jvm.compiler;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.kotlin.descriptors.impl.DeclarationDescriptorVisitorEmptyBodies;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.constants.ConstantValue;
import org.jetbrains.kotlin.resolve.jvm.JvmBindingContextSlices;
import org.jetbrains.kotlin.resolve.scopes.MemberScope;
import org.jetbrains.kotlin.test.Assertions;
import java.util.*;
public class ExpectedLoadErrorsUtil {
public static final String ANNOTATION_CLASS_NAME = "org.jetbrains.kotlin.jvm.compiler.annotation.ExpectLoadError";
public static void checkForLoadErrors(
@NotNull PackageViewDescriptor packageFromJava,
@NotNull BindingContext bindingContext,
@NotNull Assertions assertions
) {
Map<SourceElement, List<String>> expectedErrors = getExpectedLoadErrors(packageFromJava);
Map<SourceElement, List<String>> actualErrors = getActualLoadErrors(bindingContext);
for (SourceElement source : ContainerUtil.union(expectedErrors.keySet(), actualErrors.keySet())) {
List<String> actual = actualErrors.get(source);
List<String> expected = expectedErrors.get(source);
assertions.assertNotNull(expected, () -> "Unexpected load error(s):\n" + actual + "\ncontainer:" + source);
assertions.assertNotNull(actual, () -> "Missing load error(s):\n" + expected + "\ncontainer:" + source);
assertions.assertSameElements(actual, expected, () -> "Unexpected/missing load error(s)\ncontainer:" + source);
}
}
private static Map<SourceElement, List<String>> getExpectedLoadErrors(@NotNull PackageViewDescriptor packageFromJava) {
Map<SourceElement, List<String>> map = new HashMap<>();
packageFromJava.acceptVoid(new DeclarationDescriptorVisitorEmptyBodies<Void, Void>() {
@Override
public Void visitPackageViewDescriptor(PackageViewDescriptor descriptor, Void data) {
return visitDeclarationRecursively(descriptor, descriptor.getMemberScope());
}
@Override
public Void visitClassDescriptor(ClassDescriptor descriptor, Void data) {
return visitDeclarationRecursively(descriptor, descriptor.getDefaultType().getMemberScope());
}
@Override
public Void visitFunctionDescriptor(FunctionDescriptor descriptor, Void data) {
return visitDeclaration(descriptor);
}
@Override
public Void visitPropertyDescriptor(PropertyDescriptor descriptor, Void data) {
return visitDeclaration(descriptor);
}
private Void visitDeclaration(@NotNull DeclarationDescriptor descriptor) {
AnnotationDescriptor annotation = descriptor.getAnnotations().findAnnotation(new FqName(ANNOTATION_CLASS_NAME));
if (annotation == null) return null;
// we expect exactly one annotation argument
ConstantValue<?> argument = annotation.getAllValueArguments().values().iterator().next();
String error = (String) argument.getValue();
//noinspection ConstantConditions
List<String> errors = Arrays.asList(error.split("\\|"));
putError(map, descriptor, errors);
return null;
}
private Void visitDeclarationRecursively(@NotNull DeclarationDescriptor descriptor, @NotNull MemberScope memberScope) {
for (DeclarationDescriptor member : DescriptorUtils.getAllDescriptors(memberScope)) {
member.acceptVoid(this);
}
return visitDeclaration(descriptor);
}
});
return map;
}
private static Map<SourceElement, List<String>> getActualLoadErrors(@NotNull BindingContext bindingContext) {
Map<SourceElement, List<String>> result = new HashMap<>();
Collection<DeclarationDescriptor> descriptors = bindingContext.getKeys(JvmBindingContextSlices.LOAD_FROM_JAVA_SIGNATURE_ERRORS);
for (DeclarationDescriptor descriptor : descriptors) {
List<String> errors = bindingContext.get(JvmBindingContextSlices.LOAD_FROM_JAVA_SIGNATURE_ERRORS, descriptor);
if (errors == null) continue;
putError(result, descriptor, errors);
}
return result;
}
private static void putError(
@NotNull Map<SourceElement, List<String>> result,
@NotNull DeclarationDescriptor descriptor,
@NotNull List<String> errors
) {
assert descriptor.getOriginal() instanceof DeclarationDescriptorWithSource
: "Signature errors should be reported only on declarations with source, but " + descriptor + " found";
result.put(((DeclarationDescriptorWithSource) descriptor.getOriginal()).getSource(), errors);
}
private ExpectedLoadErrorsUtil() {
}
}
@@ -0,0 +1,560 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.test.util;
import com.google.common.collect.Lists;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.scopes.MemberScope;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.types.KotlinTypeKt;
import java.io.PrintStream;
import java.util.Collection;
import java.util.List;
import java.util.function.Predicate;
public class DescriptorValidator {
public static void validate(@NotNull ValidationVisitor validationStrategy, DeclarationDescriptor descriptor) {
DiagnosticCollectorForTests collector = new DiagnosticCollectorForTests();
validate(validationStrategy, descriptor, collector);
collector.done();
}
public static void validate(
@NotNull ValidationVisitor validator,
@NotNull DeclarationDescriptor descriptor,
@NotNull DiagnosticCollector collector
) {
RecursiveDescriptorProcessor.process(descriptor, collector, validator);
}
private static void report(@NotNull DiagnosticCollector collector, @NotNull DeclarationDescriptor descriptor, @NotNull String message) {
collector.report(new ValidationDiagnostic(descriptor, message));
}
public interface DiagnosticCollector {
void report(@NotNull ValidationDiagnostic diagnostic);
}
public static class ValidationVisitor implements DeclarationDescriptorVisitor<Boolean, DiagnosticCollector> {
public static ValidationVisitor errorTypesForbidden() {
return new ValidationVisitor();
}
public static ValidationVisitor errorTypesAllowed() {
return new ValidationVisitor().allowErrorTypes();
}
private boolean allowErrorTypes = false;
private Predicate<DeclarationDescriptor> recursiveFilter = descriptor -> true;
protected ValidationVisitor() {
}
@NotNull
public ValidationVisitor withStepIntoFilter(@NotNull Predicate<DeclarationDescriptor> filter) {
this.recursiveFilter = filter;
return this;
}
@NotNull
public ValidationVisitor allowErrorTypes() {
this.allowErrorTypes = true;
return this;
}
protected void validateScope(DeclarationDescriptor scopeOwner, @NotNull MemberScope scope, @NotNull DiagnosticCollector collector) {
for (DeclarationDescriptor descriptor : DescriptorUtils.getAllDescriptors(scope)) {
if (recursiveFilter.test(descriptor)) {
descriptor.accept(new ScopeValidatorVisitor(collector), scope);
}
}
}
private void validateType(
@NotNull DeclarationDescriptor descriptor,
@Nullable KotlinType type,
@NotNull DiagnosticCollector collector
) {
if (type == null) {
report(collector, descriptor, "No type");
return;
}
if (!allowErrorTypes && KotlinTypeKt.isError(type)) {
report(collector, descriptor, "Error type: " + type);
return;
}
validateScope(descriptor, type.getMemberScope(), collector);
}
private void validateReturnType(CallableDescriptor descriptor, DiagnosticCollector collector) {
validateType(descriptor, descriptor.getReturnType(), collector);
}
private static void validateTypeParameters(DiagnosticCollector collector, List<TypeParameterDescriptor> parameters) {
for (int i = 0; i < parameters.size(); i++) {
TypeParameterDescriptor typeParameterDescriptor = parameters.get(i);
if (typeParameterDescriptor.getIndex() != i) {
report(collector, typeParameterDescriptor, "Incorrect index: " + typeParameterDescriptor.getIndex() + " but must be " + i);
}
}
}
private static void validateValueParameters(DiagnosticCollector collector, List<ValueParameterDescriptor> parameters) {
for (int i = 0; i < parameters.size(); i++) {
ValueParameterDescriptor valueParameterDescriptor = parameters.get(i);
if (valueParameterDescriptor.getIndex() != i) {
report(collector, valueParameterDescriptor, "Incorrect index: " + valueParameterDescriptor.getIndex() + " but must be " + i);
}
}
}
private void validateTypes(
DeclarationDescriptor descriptor,
DiagnosticCollector collector,
Collection<KotlinType> types
) {
for (KotlinType type : types) {
validateType(descriptor, type, collector);
}
}
private void validateCallable(CallableDescriptor descriptor, DiagnosticCollector collector) {
validateReturnType(descriptor, collector);
validateTypeParameters(collector, descriptor.getTypeParameters());
validateValueParameters(collector, descriptor.getValueParameters());
}
private static <T> void assertEquals(
DeclarationDescriptor descriptor,
DiagnosticCollector collector,
String name,
T expected,
T actual
) {
if (!expected.equals(actual)) {
report(collector, descriptor, "Wrong " + name + ": " + actual + " must be " + expected);
}
}
private static <T> void assertEqualTypes(
DeclarationDescriptor descriptor,
DiagnosticCollector collector,
String name,
KotlinType expected,
KotlinType actual
) {
if (KotlinTypeKt.isError(expected) && KotlinTypeKt.isError(actual)) {
assertEquals(descriptor, collector, name, expected.toString(), actual.toString());
}
else if (!expected.equals(actual)) {
report(collector, descriptor, "Wrong " + name + ": " + actual + " must be " + expected);
}
}
private static void validateAccessor(
PropertyDescriptor descriptor,
DiagnosticCollector collector,
PropertyAccessorDescriptor accessor,
String name
) {
// TODO: fix the discrepancies in descriptor construction and enable these checks
//assertEquals(accessor, collector, name + " visibility", descriptor.getVisibility(), accessor.getVisibility());
//assertEquals(accessor, collector, name + " modality", descriptor.getModality(), accessor.getModality());
assertEquals(accessor, collector, "corresponding property", descriptor, accessor.getCorrespondingProperty());
}
@Override
public Boolean visitPackageFragmentDescriptor(
PackageFragmentDescriptor descriptor, DiagnosticCollector collector
) {
validateScope(descriptor, descriptor.getMemberScope(), collector);
return true;
}
@Override
public Boolean visitPackageViewDescriptor(PackageViewDescriptor descriptor, DiagnosticCollector collector) {
if (!recursiveFilter.test(descriptor)) return false;
validateScope(descriptor, descriptor.getMemberScope(), collector);
return true;
}
@Override
public Boolean visitVariableDescriptor(
VariableDescriptor descriptor, DiagnosticCollector collector
) {
validateReturnType(descriptor, collector);
return true;
}
@Override
public Boolean visitFunctionDescriptor(
FunctionDescriptor descriptor, DiagnosticCollector collector
) {
validateCallable(descriptor, collector);
return true;
}
@Override
public Boolean visitTypeParameterDescriptor(
TypeParameterDescriptor descriptor, DiagnosticCollector collector
) {
validateTypes(descriptor, collector, descriptor.getUpperBounds());
validateType(descriptor, descriptor.getDefaultType(), collector);
return true;
}
@Override
public Boolean visitClassDescriptor(
ClassDescriptor descriptor, DiagnosticCollector collector
) {
validateTypeParameters(collector, descriptor.getDeclaredTypeParameters());
Collection<KotlinType> supertypes = descriptor.getTypeConstructor().getSupertypes();
if (supertypes.isEmpty() && descriptor.getKind() != ClassKind.INTERFACE
&& !KotlinBuiltIns.isSpecialClassWithNoSupertypes(descriptor)) {
report(collector, descriptor, "No supertypes for non-trait");
}
validateTypes(descriptor, collector, supertypes);
validateType(descriptor, descriptor.getDefaultType(), collector);
validateScope(descriptor, descriptor.getUnsubstitutedInnerClassesScope(), collector);
List<ConstructorDescriptor> primary = Lists.newArrayList();
for (ConstructorDescriptor constructorDescriptor : descriptor.getConstructors()) {
if (constructorDescriptor.isPrimary()) {
primary.add(constructorDescriptor);
}
}
if (primary.size() > 1) {
report(collector, descriptor, "Many primary constructors: " + primary);
}
ConstructorDescriptor primaryConstructor = descriptor.getUnsubstitutedPrimaryConstructor();
if (primaryConstructor != null) {
if (!descriptor.getConstructors().contains(primaryConstructor)) {
report(collector, primaryConstructor,
"Primary constructor not in getConstructors() result: " + descriptor.getConstructors());
}
}
ClassDescriptor companionObjectDescriptor = descriptor.getCompanionObjectDescriptor();
if (companionObjectDescriptor != null && !companionObjectDescriptor.isCompanionObject()) {
report(collector, companionObjectDescriptor, "Companion object should be marked as such");
}
return true;
}
@Override
public Boolean visitTypeAliasDescriptor(
TypeAliasDescriptor descriptor, DiagnosticCollector data
) {
// TODO typealias
return true;
}
@Override
public Boolean visitModuleDeclaration(
ModuleDescriptor descriptor, DiagnosticCollector collector
) {
return true;
}
@Override
public Boolean visitConstructorDescriptor(
ConstructorDescriptor constructorDescriptor, DiagnosticCollector collector
) {
visitFunctionDescriptor(constructorDescriptor, collector);
assertEqualTypes(constructorDescriptor, collector,
"return type",
constructorDescriptor.getContainingDeclaration().getDefaultType(),
constructorDescriptor.getReturnType());
return true;
}
@Override
public Boolean visitScriptDescriptor(
ScriptDescriptor scriptDescriptor, DiagnosticCollector collector
) {
return true;
}
@Override
public Boolean visitPropertyDescriptor(
PropertyDescriptor descriptor, DiagnosticCollector collector
) {
validateCallable(descriptor, collector);
PropertyGetterDescriptor getter = descriptor.getGetter();
if (getter != null) {
assertEqualTypes(getter, collector, "getter return type", descriptor.getType(), getter.getReturnType());
validateAccessor(descriptor, collector, getter, "getter");
}
PropertySetterDescriptor setter = descriptor.getSetter();
if (setter != null) {
assertEquals(setter, collector, "setter parameter count", 1, setter.getValueParameters().size());
assertEqualTypes(setter, collector, "setter parameter type", descriptor.getType(), setter.getValueParameters().get(0).getType());
assertEquals(setter, collector, "corresponding property", descriptor, setter.getCorrespondingProperty());
}
return true;
}
@Override
public Boolean visitValueParameterDescriptor(
ValueParameterDescriptor descriptor, DiagnosticCollector collector
) {
return visitVariableDescriptor(descriptor, collector);
}
@Override
public Boolean visitPropertyGetterDescriptor(
PropertyGetterDescriptor descriptor, DiagnosticCollector collector
) {
return visitFunctionDescriptor(descriptor, collector);
}
@Override
public Boolean visitPropertySetterDescriptor(
PropertySetterDescriptor descriptor, DiagnosticCollector collector
) {
return visitFunctionDescriptor(descriptor, collector);
}
@Override
public Boolean visitReceiverParameterDescriptor(
ReceiverParameterDescriptor descriptor, DiagnosticCollector collector
) {
validateType(descriptor, descriptor.getType(), collector);
return true;
}
}
private static class ScopeValidatorVisitor implements DeclarationDescriptorVisitor<Void, MemberScope> {
private final DiagnosticCollector collector;
public ScopeValidatorVisitor(DiagnosticCollector collector) {
this.collector = collector;
}
private void report(DeclarationDescriptor expected, String message) {
DescriptorValidator.report(collector, expected, message);
}
private void assertFound(
@NotNull MemberScope scope,
@NotNull DeclarationDescriptor expected,
@Nullable DeclarationDescriptor found,
boolean shouldBeSame
) {
if (found == null) {
report(expected, "Not found in " + scope);
}
if (shouldBeSame ? expected != found : !expected.equals(found)) {
report(expected, "Lookup error in " + scope + ": " + found);
}
}
private void assertFound(
@NotNull MemberScope scope,
@NotNull DeclarationDescriptor expected,
@NotNull Collection<? extends DeclarationDescriptor> found
) {
if (!found.contains(expected)) {
report(expected, "Not found in " + scope + ": " + found);
}
}
@Override
public Void visitPackageFragmentDescriptor(
PackageFragmentDescriptor descriptor, MemberScope scope
) {
return null;
}
@Override
public Void visitPackageViewDescriptor(
PackageViewDescriptor descriptor, MemberScope scope
) {
return null;
}
@Override
public Void visitVariableDescriptor(
VariableDescriptor descriptor, MemberScope scope
) {
assertFound(scope, descriptor, scope.getContributedVariables(descriptor.getName(), NoLookupLocation.FROM_TEST));
return null;
}
@Override
public Void visitFunctionDescriptor(
FunctionDescriptor descriptor, MemberScope scope
) {
assertFound(scope, descriptor, scope.getContributedFunctions(descriptor.getName(), NoLookupLocation.FROM_TEST));
return null;
}
@Override
public Void visitTypeParameterDescriptor(
TypeParameterDescriptor descriptor, MemberScope scope
) {
assertFound(scope, descriptor, scope.getContributedClassifier(descriptor.getName(), NoLookupLocation.FROM_TEST), true);
return null;
}
@Override
public Void visitClassDescriptor(
ClassDescriptor descriptor, MemberScope scope
) {
assertFound(scope, descriptor, scope.getContributedClassifier(descriptor.getName(), NoLookupLocation.FROM_TEST), true);
return null;
}
@Override
public Void visitTypeAliasDescriptor(TypeAliasDescriptor descriptor, MemberScope data) {
// TODO typealias
return null;
}
@Override
public Void visitModuleDeclaration(
ModuleDescriptor descriptor, MemberScope scope
) {
report(descriptor, "Module found in scope: " + scope);
return null;
}
@Override
public Void visitConstructorDescriptor(
ConstructorDescriptor descriptor, MemberScope scope
) {
report(descriptor, "Constructor found in scope: " + scope);
return null;
}
@Override
public Void visitScriptDescriptor(
ScriptDescriptor descriptor, MemberScope scope
) {
report(descriptor, "Script found in scope: " + scope);
return null;
}
@Override
public Void visitPropertyDescriptor(
PropertyDescriptor descriptor, MemberScope scope
) {
return visitVariableDescriptor(descriptor, scope);
}
@Override
public Void visitValueParameterDescriptor(
ValueParameterDescriptor descriptor, MemberScope scope
) {
return visitVariableDescriptor(descriptor, scope);
}
@Override
public Void visitPropertyGetterDescriptor(
PropertyGetterDescriptor descriptor, MemberScope scope
) {
report(descriptor, "Getter found in scope: " + scope);
return null;
}
@Override
public Void visitPropertySetterDescriptor(
PropertySetterDescriptor descriptor, MemberScope scope
) {
report(descriptor, "Setter found in scope: " + scope);
return null;
}
@Override
public Void visitReceiverParameterDescriptor(
ReceiverParameterDescriptor descriptor, MemberScope scope
) {
report(descriptor, "Receiver parameter found in scope: " + scope);
return null;
}
}
public static class ValidationDiagnostic {
private final DeclarationDescriptor descriptor;
private final String message;
private final Throwable stackTrace;
private ValidationDiagnostic(@NotNull DeclarationDescriptor descriptor, @NotNull String message) {
this.descriptor = descriptor;
this.message = message;
this.stackTrace = new Throwable();
}
@NotNull
public DeclarationDescriptor getDescriptor() {
return descriptor;
}
@NotNull
public String getMessage() {
return message;
}
@NotNull
public Throwable getStackTrace() {
return stackTrace;
}
public void printStackTrace(@NotNull PrintStream out) {
out.println(descriptor);
out.println(message);
stackTrace.printStackTrace(out);
}
@Override
public String toString() {
return descriptor + " > " + message;
}
}
private static class DiagnosticCollectorForTests implements DiagnosticCollector {
private boolean errorsFound = false;
@Override
public void report(@NotNull ValidationDiagnostic diagnostic) {
diagnostic.printStackTrace(System.err);
errorsFound = true;
}
public void done() {
if (errorsFound) {
throw new AssertionError("Descriptor validation failed (see messages above)");
}
}
}
private DescriptorValidator() {}
}
@@ -0,0 +1,457 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.test.util;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import kotlin.Unit;
import kotlin.text.StringsKt;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.StandardNames;
import org.jetbrains.kotlin.contracts.description.*;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.impl.SubpackagesScope;
import org.jetbrains.kotlin.jvm.compiler.ExpectedLoadErrorsUtil;
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor;
import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.platform.TargetPlatformKt;
import org.jetbrains.kotlin.renderer.*;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.MemberComparator;
import org.jetbrains.kotlin.resolve.scopes.ChainedMemberScope;
import org.jetbrains.kotlin.resolve.scopes.MemberScope;
import org.jetbrains.kotlin.test.Assertions;
import org.jetbrains.kotlin.utils.Printer;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry;
import static org.jetbrains.kotlin.test.util.DescriptorValidator.ValidationVisitor.errorTypesForbidden;
public class RecursiveDescriptorComparator {
private static final DescriptorRenderer DEFAULT_RENDERER = DescriptorRenderer.Companion.withOptions(
options -> {
options.setWithDefinedIn(false);
options.setExcludedAnnotationClasses(Collections.singleton(new FqName(ExpectedLoadErrorsUtil.ANNOTATION_CLASS_NAME)));
options.setOverrideRenderingPolicy(OverrideRenderingPolicy.RENDER_OPEN_OVERRIDE);
options.setIncludePropertyConstant(true);
options.setClassifierNamePolicy(ClassifierNamePolicy.FULLY_QUALIFIED.INSTANCE);
options.setVerbose(true);
options.setAnnotationArgumentsRenderingPolicy(AnnotationArgumentsRenderingPolicy.UNLESS_EMPTY);
options.setModifiers(DescriptorRendererModifier.ALL);
return Unit.INSTANCE;
}
);
public static final Configuration DONT_INCLUDE_METHODS_OF_OBJECT = new Configuration(false, false, false, false,
false, descriptor -> true, errorTypesForbidden(), DEFAULT_RENDERER);
public static final Configuration RECURSIVE = new Configuration(false, false, true, false,
false, descriptor -> true, errorTypesForbidden(), DEFAULT_RENDERER);
public static final Configuration RECURSIVE_ALL = new Configuration(true, true, true, false,
true, descriptor -> true, errorTypesForbidden(), DEFAULT_RENDERER);
public static final Predicate<DeclarationDescriptor> SKIP_BUILT_INS_PACKAGES = descriptor -> {
if (descriptor instanceof PackageViewDescriptor) {
return !StandardNames.BUILT_INS_PACKAGE_FQ_NAME.equals(((PackageViewDescriptor) descriptor).getFqName());
}
return true;
};
private static final ImmutableSet<String> KOTLIN_ANY_METHOD_NAMES = ImmutableSet.of("equals", "hashCode", "toString");
private final Configuration conf;
public RecursiveDescriptorComparator(@NotNull Configuration conf) {
this.conf = conf;
}
public String serializeRecursively(@NotNull DeclarationDescriptor declarationDescriptor) {
StringBuilder result = new StringBuilder();
appendDeclarationRecursively(declarationDescriptor, DescriptorUtils.getContainingModule(declarationDescriptor),
new Printer(result, 1), true);
return result.toString();
}
private void appendDeclarationRecursively(
@NotNull DeclarationDescriptor descriptor,
@NotNull ModuleDescriptor module,
@NotNull Printer printer,
boolean topLevel
) {
if (!isFromModule(descriptor, module)) return;
boolean isEnumEntry = isEnumEntry(descriptor);
boolean isClassOrPackage =
(descriptor instanceof ClassOrPackageFragmentDescriptor || descriptor instanceof PackageViewDescriptor) && !isEnumEntry;
StringBuilder content = new StringBuilder();
if (isClassOrPackage) {
Printer child = new Printer(content, printer);
if (!topLevel) {
child.pushIndent();
}
if (descriptor instanceof ClassDescriptor) {
ClassDescriptor klass = (ClassDescriptor) descriptor;
appendSubDescriptors(descriptor, module, klass.getDefaultType().getMemberScope(), klass.getConstructors(), child);
MemberScope staticScope = klass.getStaticScope();
if (!DescriptorUtils.getAllDescriptors(staticScope).isEmpty()) {
child.println();
child.println("// Static members");
appendSubDescriptors(descriptor, module, staticScope, Collections.emptyList(), child);
}
}
else if (descriptor instanceof PackageFragmentDescriptor) {
appendSubDescriptors(descriptor, module,
((PackageFragmentDescriptor) descriptor).getMemberScope(),
Collections.emptyList(), child);
}
else if (descriptor instanceof PackageViewDescriptor) {
appendSubDescriptors(descriptor, module,
getPackageScopeInModule((PackageViewDescriptor) descriptor, module),
Collections.emptyList(), child);
}
if (!topLevel) {
if (child.isEmpty() && (
descriptor instanceof PackageFragmentDescriptor || descriptor instanceof PackageViewDescriptor
)) {
return;
}
printer.println();
}
}
printDescriptor(descriptor, printer);
if (isClassOrPackage) {
if (!topLevel) {
printer.printlnWithNoIndent(" {");
printer.printWithNoIndent(content);
printer.println("}");
}
else {
printer.println();
printer.println();
printer.printWithNoIndent(StringsKt.trimStart(content, Printer.LINE_SEPARATOR.toCharArray()));
}
}
else if (conf.checkPropertyAccessors && descriptor instanceof PropertyDescriptor) {
printer.printlnWithNoIndent();
printer.pushIndent();
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
PropertyGetterDescriptor getter = propertyDescriptor.getGetter();
if (getter != null) {
printer.println(conf.renderer.render(getter));
}
PropertySetterDescriptor setter = propertyDescriptor.getSetter();
if (setter != null) {
printer.println(conf.renderer.render(setter));
}
printer.popIndent();
}
else {
printer.printlnWithNoIndent();
}
if (isEnumEntry) {
printer.println();
}
}
private void printDescriptor(
@NotNull DeclarationDescriptor descriptor,
@NotNull Printer printer
) {
boolean isPrimaryConstructor = conf.checkPrimaryConstructors &&
descriptor instanceof ConstructorDescriptor && ((ConstructorDescriptor) descriptor).isPrimary();
boolean isRecord = descriptor instanceof JavaClassDescriptor && ((JavaClassDescriptor) descriptor).isRecord();
boolean isRecordComponent = descriptor instanceof JavaMethodDescriptor && ((JavaMethodDescriptor) descriptor).isForRecordComponent();
StringBuilder prefix = new StringBuilder();
if (isPrimaryConstructor) {
prefix.append("/*primary*/ ");
}
if (isRecord) {
prefix.append("/*record*/ ");
}
if (isRecordComponent) {
prefix.append("/*record component*/ ");
}
printer.print(prefix.toString(), conf.renderer.render(descriptor));
if (descriptor instanceof FunctionDescriptor && conf.checkFunctionContracts) {
printEffectsIfAny((FunctionDescriptor) descriptor, printer);
}
}
private static void printEffectsIfAny(FunctionDescriptor functionDescriptor, Printer printer) {
AbstractContractProvider contractProvider = functionDescriptor.getUserData(ContractProviderKey.INSTANCE);
if (contractProvider == null) return;
ContractDescription contractDescription = contractProvider.getContractDescription();
if (contractDescription == null || contractDescription.getEffects().isEmpty()) return;
printer.println();
printer.pushIndent();
for (EffectDeclaration effect : contractDescription.getEffects()) {
StringBuilder sb = new StringBuilder();
ContractDescriptionRenderer renderer = new ContractDescriptionRenderer(sb);
effect.accept(renderer, Unit.INSTANCE);
printer.println(sb.toString());
}
printer.popIndent();
}
@NotNull
private MemberScope getPackageScopeInModule(@NotNull PackageViewDescriptor descriptor, @NotNull ModuleDescriptor module) {
// See LazyPackageViewDescriptorImpl#memberScope
List<MemberScope> scopes = new ArrayList<>();
for (PackageFragmentDescriptor fragment : descriptor.getFragments()) {
if (isFromModule(fragment, module)) {
scopes.add(fragment.getMemberScope());
}
}
scopes.add(new SubpackagesScope(module, descriptor.getFqName()));
return ChainedMemberScope.Companion.create("test", scopes);
}
private boolean isFromModule(@NotNull DeclarationDescriptor descriptor, @NotNull ModuleDescriptor module) {
if (conf.renderDeclarationsFromOtherModules) return true;
if (descriptor instanceof PackageViewDescriptor) {
// PackageViewDescriptor does not belong to any module, so we check if one of its containing fragments is in our module
for (PackageFragmentDescriptor fragment : ((PackageViewDescriptor) descriptor).getFragments()) {
if (module.equals(DescriptorUtils.getContainingModule(fragment))) return true;
}
}
// 'expected' declarations do not belong to the platform-specific module, even though they participate in the analysis
if (descriptor instanceof MemberDescriptor && ((MemberDescriptor) descriptor).isExpect() &&
!TargetPlatformKt.isCommon(module.getPlatform())) return false;
return module.equals(DescriptorUtils.getContainingModule(descriptor));
}
private boolean shouldSkip(@NotNull DeclarationDescriptor subDescriptor) {
boolean isFunctionFromAny = subDescriptor.getContainingDeclaration() instanceof ClassDescriptor
&& subDescriptor instanceof FunctionDescriptor
&& KOTLIN_ANY_METHOD_NAMES.contains(subDescriptor.getName().asString());
return (isFunctionFromAny && !conf.includeMethodsOfKotlinAny) || !conf.recursiveFilter.test(subDescriptor);
}
private void appendSubDescriptors(
@NotNull DeclarationDescriptor descriptor,
@NotNull ModuleDescriptor module,
@NotNull MemberScope memberScope,
@NotNull Collection<? extends DeclarationDescriptor> extraSubDescriptors,
@NotNull Printer printer
) {
if (!isFromModule(descriptor, module)) return;
List<DeclarationDescriptor> subDescriptors = Lists.newArrayList();
subDescriptors.addAll(DescriptorUtils.getAllDescriptors(memberScope));
subDescriptors.addAll(extraSubDescriptors);
subDescriptors.sort(MemberComparator.INSTANCE);
for (DeclarationDescriptor subDescriptor : subDescriptors) {
if (!shouldSkip(subDescriptor)) {
appendDeclarationRecursively(subDescriptor, module, printer, false);
}
}
}
private static void compareDescriptorWithFile(
@NotNull DeclarationDescriptor actual,
@NotNull Configuration configuration,
@NotNull File txtFile,
@NotNull Assertions assertions
) {
doCompareDescriptors(null, actual, configuration, txtFile, assertions);
}
public static void compareDescriptors(
@NotNull DeclarationDescriptor expected,
@NotNull DeclarationDescriptor actual,
@NotNull Configuration configuration,
@Nullable File txtFile,
@NotNull Assertions assertions
) {
if (expected == actual) {
throw new IllegalArgumentException("Don't invoke this method with expected == actual." +
"Invoke compareDescriptorWithFile() instead.");
}
doCompareDescriptors(expected, actual, configuration, txtFile, assertions);
}
public static void validateAndCompareDescriptorWithFile(
@NotNull DeclarationDescriptor actual,
@NotNull Configuration configuration,
@NotNull File txtFile,
@NotNull Assertions assertions
) {
DescriptorValidator.validate(configuration.validationStrategy, actual);
compareDescriptorWithFile(actual, configuration, txtFile, assertions);
}
public static void validateAndCompareDescriptors(
@NotNull DeclarationDescriptor expected,
@NotNull DeclarationDescriptor actual,
@NotNull Configuration configuration,
@Nullable File txtFile,
@NotNull Assertions assertions
) {
DescriptorValidator.validate(configuration.validationStrategy, expected);
DescriptorValidator.validate(configuration.validationStrategy, actual);
compareDescriptors(expected, actual, configuration, txtFile, assertions);
}
private static void doCompareDescriptors(
@Nullable DeclarationDescriptor expected,
@NotNull DeclarationDescriptor actual,
@NotNull Configuration configuration,
@Nullable File txtFile,
@NotNull Assertions assertions
) {
RecursiveDescriptorComparator comparator = new RecursiveDescriptorComparator(configuration);
String actualSerialized = comparator.serializeRecursively(actual);
if (expected != null) {
String expectedSerialized = comparator.serializeRecursively(expected);
assertions.assertEquals(expectedSerialized, actualSerialized, () -> "Expected and actual descriptors differ");
}
if (txtFile != null) {
assertions.assertEqualsToFile(txtFile, actualSerialized, (s) -> s);
}
}
public static class Configuration {
private final boolean checkPrimaryConstructors;
private final boolean checkPropertyAccessors;
private final boolean includeMethodsOfKotlinAny;
private final boolean renderDeclarationsFromOtherModules;
private final boolean checkFunctionContracts;
private final Predicate<DeclarationDescriptor> recursiveFilter;
private final DescriptorRenderer renderer;
private final DescriptorValidator.ValidationVisitor validationStrategy;
public Configuration(
boolean checkPrimaryConstructors,
boolean checkPropertyAccessors,
boolean includeMethodsOfKotlinAny,
boolean renderDeclarationsFromOtherModules,
boolean checkFunctionContracts,
Predicate<DeclarationDescriptor> recursiveFilter,
DescriptorValidator.ValidationVisitor validationStrategy,
DescriptorRenderer renderer
) {
this.checkPrimaryConstructors = checkPrimaryConstructors;
this.checkPropertyAccessors = checkPropertyAccessors;
this.includeMethodsOfKotlinAny = includeMethodsOfKotlinAny;
this.renderDeclarationsFromOtherModules = renderDeclarationsFromOtherModules;
this.checkFunctionContracts = checkFunctionContracts;
this.recursiveFilter = recursiveFilter;
this.validationStrategy = validationStrategy;
this.renderer = rendererWithPropertyAccessors(renderer, checkPropertyAccessors);
}
public Configuration filterRecursion(@NotNull Predicate<DeclarationDescriptor> stepIntoFilter) {
return new Configuration(checkPrimaryConstructors, checkPropertyAccessors, includeMethodsOfKotlinAny,
renderDeclarationsFromOtherModules, checkFunctionContracts, stepIntoFilter,
validationStrategy.withStepIntoFilter(stepIntoFilter), renderer);
}
public Configuration checkPrimaryConstructors(boolean checkPrimaryConstructors) {
return new Configuration(checkPrimaryConstructors, checkPropertyAccessors, includeMethodsOfKotlinAny,
renderDeclarationsFromOtherModules, checkFunctionContracts, recursiveFilter, validationStrategy, renderer);
}
public Configuration checkPropertyAccessors(boolean checkPropertyAccessors) {
return new Configuration(
checkPrimaryConstructors, checkPropertyAccessors, includeMethodsOfKotlinAny, renderDeclarationsFromOtherModules,
checkFunctionContracts, recursiveFilter, validationStrategy,
rendererWithPropertyAccessors(renderer, checkPropertyAccessors)
);
}
public Configuration checkFunctionContracts(boolean checkFunctionContracts) {
return new Configuration(checkPrimaryConstructors, checkPropertyAccessors, includeMethodsOfKotlinAny,
renderDeclarationsFromOtherModules, checkFunctionContracts, recursiveFilter, validationStrategy, renderer);
}
public Configuration includeMethodsOfKotlinAny(boolean includeMethodsOfKotlinAny) {
return new Configuration(checkPrimaryConstructors, checkPropertyAccessors, includeMethodsOfKotlinAny,
renderDeclarationsFromOtherModules, checkFunctionContracts, recursiveFilter, validationStrategy, renderer);
}
public Configuration renderDeclarationsFromOtherModules(boolean renderDeclarationsFromOtherModules) {
return new Configuration(checkPrimaryConstructors, checkPropertyAccessors, includeMethodsOfKotlinAny,
renderDeclarationsFromOtherModules, checkFunctionContracts, recursiveFilter, validationStrategy, renderer);
}
public Configuration withValidationStrategy(@NotNull DescriptorValidator.ValidationVisitor validationStrategy) {
return new Configuration(checkPrimaryConstructors, checkPropertyAccessors, includeMethodsOfKotlinAny,
renderDeclarationsFromOtherModules, checkFunctionContracts, recursiveFilter, validationStrategy, renderer);
}
public Configuration withRenderer(@NotNull DescriptorRenderer renderer) {
return new Configuration(checkPrimaryConstructors, checkPropertyAccessors, includeMethodsOfKotlinAny,
renderDeclarationsFromOtherModules, checkFunctionContracts, recursiveFilter, validationStrategy, renderer);
}
public Configuration withRendererOptions(@NotNull Consumer<DescriptorRendererOptions> configure) {
return new Configuration(
checkPrimaryConstructors, checkPropertyAccessors, includeMethodsOfKotlinAny,
renderDeclarationsFromOtherModules, checkFunctionContracts, recursiveFilter, validationStrategy,
newRenderer(renderer, configure));
}
@NotNull
private static DescriptorRenderer rendererWithPropertyAccessors(
@NotNull DescriptorRenderer renderer, boolean checkPropertyAccessors
) {
return newRenderer(renderer, options ->
options.setPropertyAccessorRenderingPolicy(
checkPropertyAccessors ? PropertyAccessorRenderingPolicy.DEBUG : PropertyAccessorRenderingPolicy.NONE
)
);
}
@NotNull
private static DescriptorRenderer newRenderer(
@NotNull DescriptorRenderer renderer, @NotNull Consumer<DescriptorRendererOptions> configure
) {
return renderer.withOptions(options -> {
configure.accept(options);
return Unit.INSTANCE;
});
}
}
}
@@ -0,0 +1,154 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.test.util;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import java.util.Collection;
public class RecursiveDescriptorProcessor {
public static <D> boolean process(
@NotNull DeclarationDescriptor descriptor,
D data,
@NotNull DeclarationDescriptorVisitor<Boolean, D> visitor
) {
return descriptor.accept(new RecursiveVisitor<>(visitor), data);
}
private static class RecursiveVisitor<D> implements DeclarationDescriptorVisitor<Boolean, D> {
private final DeclarationDescriptorVisitor<Boolean, D> worker;
private RecursiveVisitor(@NotNull DeclarationDescriptorVisitor<Boolean, D> worker) {
this.worker = worker;
}
private boolean visitChildren(Collection<? extends DeclarationDescriptor> descriptors, D data) {
for (DeclarationDescriptor descriptor : descriptors) {
if (!descriptor.accept(this, data)) return false;
}
return true;
}
private boolean visitChildren(@Nullable DeclarationDescriptor descriptor, D data) {
if (descriptor == null) return true;
return descriptor.accept(this, data);
}
private boolean applyWorker(@NotNull DeclarationDescriptor descriptor, D data) {
return descriptor.accept(worker, data);
}
private boolean processCallable(CallableDescriptor descriptor, D data) {
return applyWorker(descriptor, data)
&& visitChildren(descriptor.getTypeParameters(), data)
&& visitChildren(descriptor.getExtensionReceiverParameter(), data)
&& visitChildren(descriptor.getValueParameters(), data);
}
@Override
public Boolean visitPackageFragmentDescriptor(PackageFragmentDescriptor descriptor, D data) {
return applyWorker(descriptor, data)
&& visitChildren(DescriptorUtils.getAllDescriptors(descriptor.getMemberScope()), data);
}
@Override
public Boolean visitPackageViewDescriptor(PackageViewDescriptor descriptor, D data) {
return applyWorker(descriptor, data)
&& visitChildren(DescriptorUtils.getAllDescriptors(descriptor.getMemberScope()), data);
}
@Override
public Boolean visitVariableDescriptor(VariableDescriptor descriptor, D data) {
return processCallable(descriptor, data);
}
@Override
public Boolean visitPropertyDescriptor(PropertyDescriptor descriptor, D data) {
return processCallable(descriptor, data)
&& visitChildren(descriptor.getGetter(), data)
&& visitChildren(descriptor.getSetter(), data);
}
@Override
public Boolean visitFunctionDescriptor(FunctionDescriptor descriptor, D data) {
return processCallable(descriptor, data);
}
@Override
public Boolean visitTypeParameterDescriptor(TypeParameterDescriptor descriptor, D data) {
return applyWorker(descriptor, data);
}
@Override
public Boolean visitClassDescriptor(ClassDescriptor descriptor, D data) {
return applyWorker(descriptor, data)
&& visitChildren(descriptor.getThisAsReceiverParameter(), data)
&& visitChildren(descriptor.getConstructors(), data)
&& visitChildren(descriptor.getTypeConstructor().getParameters(), data)
&& visitChildren(DescriptorUtils.getAllDescriptors(descriptor.getDefaultType().getMemberScope()), data);
}
@Override
public Boolean visitTypeAliasDescriptor(TypeAliasDescriptor descriptor, D data) {
return applyWorker(descriptor, data)
&& visitChildren(descriptor.getDeclaredTypeParameters(), data);
}
@Override
public Boolean visitModuleDeclaration(ModuleDescriptor descriptor, D data) {
return applyWorker(descriptor, data)
&& visitChildren(descriptor.getPackage(FqName.ROOT), data);
}
@Override
public Boolean visitConstructorDescriptor(ConstructorDescriptor constructorDescriptor, D data) {
return visitFunctionDescriptor(constructorDescriptor, data);
}
@Override
public Boolean visitScriptDescriptor(ScriptDescriptor scriptDescriptor, D data) {
return visitClassDescriptor(scriptDescriptor, data);
}
@Override
public Boolean visitValueParameterDescriptor(ValueParameterDescriptor descriptor, D data) {
return visitVariableDescriptor(descriptor, data);
}
@Override
public Boolean visitPropertyGetterDescriptor(PropertyGetterDescriptor descriptor, D data) {
return visitFunctionDescriptor(descriptor, data);
}
@Override
public Boolean visitPropertySetterDescriptor(PropertySetterDescriptor descriptor, D data) {
return visitFunctionDescriptor(descriptor, data);
}
@Override
public Boolean visitReceiverParameterDescriptor(ReceiverParameterDescriptor descriptor, D data) {
return applyWorker(descriptor, data);
}
}
}