diff --git a/compiler/tests/org/jetbrains/jet/jvm/compiler/AbstractCompileKotlinAgainstCustomJavaTest.java b/compiler/tests/org/jetbrains/jet/jvm/compiler/AbstractCompileKotlinAgainstCustomJavaTest.java index 9982f0808be..8a6f8df3a38 100644 --- a/compiler/tests/org/jetbrains/jet/jvm/compiler/AbstractCompileKotlinAgainstCustomJavaTest.java +++ b/compiler/tests/org/jetbrains/jet/jvm/compiler/AbstractCompileKotlinAgainstCustomJavaTest.java @@ -34,6 +34,7 @@ import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.java.AnalyzerFacadeForJVM; import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.test.TestCaseWithTmpdir; +import org.jetbrains.jet.test.util.DescriptorValidator; import org.jetbrains.jet.test.util.NamespaceComparator; import org.junit.Assert; @@ -70,6 +71,7 @@ public abstract class AbstractCompileKotlinAgainstCustomJavaTest extends TestCas NamespaceDescriptor namespaceDescriptor = bindingContext.get(BindingContext.FQNAME_TO_NAMESPACE_DESCRIPTOR, namespaceFqn); assertNotNull("Failed to find namespace: " + namespaceFqn, namespaceDescriptor); + DescriptorValidator.validate(namespaceDescriptor); compareNamespaceWithFile(namespaceDescriptor, NamespaceComparator.DONT_INCLUDE_METHODS_OF_OBJECT, expectedFile); } diff --git a/compiler/tests/org/jetbrains/jet/jvm/compiler/AbstractLoadCompiledKotlinTest.java b/compiler/tests/org/jetbrains/jet/jvm/compiler/AbstractLoadCompiledKotlinTest.java index c9c3adaf9e8..a32f2ad7a0a 100644 --- a/compiler/tests/org/jetbrains/jet/jvm/compiler/AbstractLoadCompiledKotlinTest.java +++ b/compiler/tests/org/jetbrains/jet/jvm/compiler/AbstractLoadCompiledKotlinTest.java @@ -23,6 +23,7 @@ import org.jetbrains.jet.analyzer.AnalyzeExhaust; import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.test.TestCaseWithTmpdir; +import org.jetbrains.jet.test.util.DescriptorValidator; import org.jetbrains.jet.test.util.NamespaceComparator; import java.io.File; @@ -55,8 +56,12 @@ public abstract class AbstractLoadCompiledKotlinTest extends TestCaseWithTmpdir TEST_PACKAGE_FQNAME); assert namespaceFromSource != null; Assert.assertEquals("test", namespaceFromSource.getName().asString()); + + DescriptorValidator.validate(namespaceFromSource); + NamespaceDescriptor namespaceFromClass = LoadDescriptorUtil.loadTestNamespaceAndBindingContextFromJavaRoot( tmpdir, getTestRootDisposable(), ConfigurationKind.JDK_ONLY).first; + compareNamespaces(namespaceFromSource, namespaceFromClass, NamespaceComparator.DONT_INCLUDE_METHODS_OF_OBJECT .checkPrimaryConstructors(true) diff --git a/compiler/tests/org/jetbrains/jet/jvm/compiler/AbstractLoadJavaTest.java b/compiler/tests/org/jetbrains/jet/jvm/compiler/AbstractLoadJavaTest.java index 2c2435d95ae..f4809446297 100644 --- a/compiler/tests/org/jetbrains/jet/jvm/compiler/AbstractLoadJavaTest.java +++ b/compiler/tests/org/jetbrains/jet/jvm/compiler/AbstractLoadJavaTest.java @@ -42,6 +42,7 @@ import org.jetbrains.jet.lang.resolve.java.AnalyzerFacadeForJVM; import org.jetbrains.jet.lang.resolve.java.DescriptorSearchRule; import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver; import org.jetbrains.jet.test.TestCaseWithTmpdir; +import org.jetbrains.jet.test.util.DescriptorValidator; import org.junit.Assert; import java.io.File; @@ -164,6 +165,7 @@ public abstract class AbstractLoadJavaTest extends TestCaseWithTmpdir { LoadDescriptorUtil.TEST_PACKAGE_FQNAME, DescriptorSearchRule.INCLUDE_KOTLIN); assert namespaceDescriptor != null : "Test namespace not found"; + DescriptorValidator.validate(namespaceDescriptor); checkJavaNamespace(expectedFile, namespaceDescriptor, trace.getBindingContext(), DONT_INCLUDE_METHODS_OF_OBJECT); } diff --git a/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadDescriptorUtil.java b/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadDescriptorUtil.java index 914a028735b..22f22563599 100644 --- a/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadDescriptorUtil.java +++ b/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadDescriptorUtil.java @@ -28,9 +28,9 @@ import org.jetbrains.jet.analyzer.AnalyzeExhaust; import org.jetbrains.jet.cli.jvm.compiler.CompileEnvironmentUtil; import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment; import org.jetbrains.jet.codegen.ClassFileFactory; -import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.codegen.GenerationUtils; import org.jetbrains.jet.codegen.forTestCompile.ForTestCompileRuntime; +import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.config.CompilerConfiguration; import org.jetbrains.jet.di.InjectorForJavaSemanticServices; import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; @@ -42,13 +42,15 @@ import org.jetbrains.jet.lang.resolve.java.DescriptorSearchRule; import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver; import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.Name; +import org.jetbrains.jet.test.util.DescriptorValidator; import java.io.File; import java.io.IOException; -import java.util.*; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; import static org.jetbrains.jet.JetTestUtils.createEnvironmentWithMockJdkAndIdeaAnnotations; -import static org.jetbrains.jet.lang.psi.JetPsiFactory.createFile; public final class LoadDescriptorUtil { @@ -105,6 +107,8 @@ public final class LoadDescriptorUtil { NamespaceDescriptor namespaceDescriptor = javaDescriptorResolver.resolveNamespace(TEST_PACKAGE_FQNAME, DescriptorSearchRule.ERROR_IF_FOUND_IN_KOTLIN); assert namespaceDescriptor != null; + + DescriptorValidator.validate(namespaceDescriptor); return Pair.create(namespaceDescriptor, injector.getBindingTrace().getBindingContext()); } @@ -137,6 +141,7 @@ public final class LoadDescriptorUtil { NamespaceDescriptor namespace = fileAndExhaust.getExhaust().getBindingContext().get(BindingContext.FQNAME_TO_NAMESPACE_DESCRIPTOR, TEST_PACKAGE_FQNAME); assert namespace != null: TEST_PACKAGE_FQNAME + " package not found in " + ktFile.getName(); + DescriptorValidator.validate(namespace); return namespace; } diff --git a/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadKotlinCustomTest.java b/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadKotlinCustomTest.java index 35b1121ad78..7d990d68ca5 100644 --- a/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadKotlinCustomTest.java +++ b/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadKotlinCustomTest.java @@ -22,6 +22,7 @@ import org.jetbrains.jet.analyzer.AnalyzeExhaust; import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.test.TestCaseWithTmpdir; +import org.jetbrains.jet.test.util.DescriptorValidator; import org.jetbrains.jet.test.util.NamespaceComparator; import java.io.File; @@ -44,7 +45,6 @@ public final class LoadKotlinCustomTest extends TestCaseWithTmpdir { throws Exception { NamespaceDescriptor namespaceFromClass = compileKotlinAndLoadTestNamespaceDescriptorFromBinary(kotlinFile, tmpdir, myTestRootDisposable, ConfigurationKind.JDK_ONLY); - compareNamespaceWithFile(namespaceFromClass, DONT_INCLUDE_METHODS_OF_OBJECT, expectedFile); } @@ -54,6 +54,7 @@ public final class LoadKotlinCustomTest extends TestCaseWithTmpdir { NamespaceDescriptor namespaceFromSource = exhaust.getBindingContext().get(BindingContext.FQNAME_TO_NAMESPACE_DESCRIPTOR, TEST_PACKAGE_FQNAME); assert namespaceFromSource != null; + DescriptorValidator.validate(namespaceFromSource); compareNamespaceWithFile(namespaceFromSource, NamespaceComparator.DONT_INCLUDE_METHODS_OF_OBJECT.checkPrimaryConstructors(true), expectedFile); } diff --git a/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/AbstractLazyResolveDiagnosticsTest.java b/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/AbstractLazyResolveDiagnosticsTest.java index 273be52f1bf..6cea9ee3eb0 100644 --- a/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/AbstractLazyResolveDiagnosticsTest.java +++ b/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/AbstractLazyResolveDiagnosticsTest.java @@ -26,6 +26,7 @@ import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe; import org.jetbrains.jet.lang.resolve.name.Name; +import org.jetbrains.jet.test.util.DescriptorValidator; import java.io.File; import java.util.List; @@ -46,6 +47,7 @@ public abstract class AbstractLazyResolveDiagnosticsTest extends AbstractJetDiag String path = JetTestUtils.getFilePath(new File(FileUtil.getRelativePath(TEST_DATA_DIR, testDataFile))); NamespaceDescriptor expected = eagerModule.getNamespace(FqName.ROOT); NamespaceDescriptor actual = lazyModule.getNamespace(FqName.ROOT); + DescriptorValidator.validate(expected, actual); String txtFileRelativePath = path.replaceAll("\\.kt$|\\.ktscript", ".txt"); File txtFile = new File("compiler/testData/lazyResolve/diagnostics/" + txtFileRelativePath); diff --git a/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/AbstractLazyResolveNamespaceComparingTest.java b/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/AbstractLazyResolveNamespaceComparingTest.java index 40f1d62812e..9b8368f3500 100644 --- a/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/AbstractLazyResolveNamespaceComparingTest.java +++ b/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/AbstractLazyResolveNamespaceComparingTest.java @@ -28,6 +28,7 @@ import org.jetbrains.jet.lang.psi.JetPsiFactory; import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; +import org.jetbrains.jet.test.util.DescriptorValidator; import org.jetbrains.jet.test.util.NamespaceComparator; import org.junit.Assert; @@ -77,6 +78,8 @@ public abstract class AbstractLazyResolveNamespaceComparingTest extends KotlinTe File serializeResultsTo = new File(FileUtil.getNameWithoutExtension(testFileName) + ".txt"); + DescriptorValidator.validate(expected, actual); + NamespaceComparator.compareNamespaces( expected, actual, NamespaceComparator.DONT_INCLUDE_METHODS_OF_OBJECT.filterRecursion( new Predicate() { diff --git a/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/LazyResolveBuiltinClassesTest.java b/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/LazyResolveBuiltinClassesTest.java index 8ab6f04fc53..ba8e3e12dbe 100644 --- a/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/LazyResolveBuiltinClassesTest.java +++ b/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/LazyResolveBuiltinClassesTest.java @@ -20,6 +20,7 @@ import org.jetbrains.jet.ConfigurationKind; import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment; import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; +import org.jetbrains.jet.test.util.DescriptorValidator; import org.junit.Test; import java.io.File; @@ -36,6 +37,7 @@ public class LazyResolveBuiltinClassesTest extends KotlinTestWithEnvironment { @Test public void testBuiltIns() throws Exception { NamespaceDescriptor builtInsPackage = KotlinBuiltIns.getInstance().getBuiltInsPackage(); + DescriptorValidator.validate(builtInsPackage); compareNamespaceWithFile(builtInsPackage, RECURSIVE, new File("compiler/testData/builtin-classes.txt")); } } diff --git a/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/LazyResolveStdlibLoadingTest.java b/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/LazyResolveStdlibLoadingTest.java index ad1460fb3aa..f79c704bf2f 100644 --- a/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/LazyResolveStdlibLoadingTest.java +++ b/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/LazyResolveStdlibLoadingTest.java @@ -29,6 +29,7 @@ import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.psi.JetPsiFactory; import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.Name; +import org.jetbrains.jet.test.util.DescriptorValidator; import org.jetbrains.jet.test.util.NamespaceComparator; import java.io.File; @@ -59,6 +60,7 @@ public class LazyResolveStdlibLoadingTest extends KotlinTestWithEnvironmentManag for (Name name : namespaceShortNames) { NamespaceDescriptor eager = module.getNamespace(FqName.topLevel(name)); NamespaceDescriptor lazy = lazyModule.getNamespace(FqName.topLevel(name)); + DescriptorValidator.validate(eager, lazy); NamespaceComparator.compareNamespaces(eager, lazy, NamespaceComparator.RECURSIVE, null); } } diff --git a/compiler/tests/org/jetbrains/jet/test/util/DescriptorValidator.java b/compiler/tests/org/jetbrains/jet/test/util/DescriptorValidator.java new file mode 100644 index 00000000000..afc2079f311 --- /dev/null +++ b/compiler/tests/org/jetbrains/jet/test/util/DescriptorValidator.java @@ -0,0 +1,506 @@ +/* + * Copyright 2010-2013 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.jet.test.util; + +import com.google.common.collect.Lists; +import junit.framework.Assert; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.resolve.scopes.JetScope; +import org.jetbrains.jet.lang.types.ErrorUtils; +import org.jetbrains.jet.lang.types.JetType; + +import java.io.PrintStream; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +public class DescriptorValidator { + + private DescriptorValidator() {} + + public static void validate(DeclarationDescriptor... descriptors) { + validate(Arrays.asList(descriptors)); + } + + public static void validate(@NotNull Collection descriptors) { + DiagnosticCollectorForTests collector = new DiagnosticCollectorForTests(); + for (DeclarationDescriptor descriptor : descriptors) { + validate(descriptor, collector); + } + collector.done(); + } + + public static void validate(@NotNull Collection descriptors, @NotNull DiagnosticCollector collector) { + for (DeclarationDescriptor descriptor : descriptors) { + validate(descriptor, collector); + } + } + + public static void validate(@NotNull DeclarationDescriptor descriptor, @NotNull DiagnosticCollector collector) { + RecursiveDescriptorProcessor.process(descriptor, collector, ValidationVisitor.INSTANCE); + } + + public interface DiagnosticCollector { + + void report(@NotNull Diagnostic diagnostic); + } + + private static void report(@NotNull DiagnosticCollector collector, @NotNull DeclarationDescriptor descriptor, @NotNull String message) { + collector.report(new Diagnostic(descriptor, message)); + } + + private static class ValidationVisitor implements DeclarationDescriptorVisitor { + + public static final ValidationVisitor INSTANCE = new ValidationVisitor(); + + private ValidationVisitor() {} + + private static void validateScope(@NotNull JetScope scope, @NotNull DiagnosticCollector collector) { + for (DeclarationDescriptor descriptor : scope.getAllDescriptors()) { + descriptor.accept(new ScopeValidatorVisitor(collector), scope); + } + } + + private static void validateType( + @NotNull DeclarationDescriptor descriptor, + @Nullable JetType type, + @NotNull DiagnosticCollector collector + ) { + if (type == null) { + report(collector, descriptor, "No type"); + return; + } + + if (ErrorUtils.isErrorType(type)) { + report(collector, descriptor, "Error type: " + type); + return; + } + + validateScope(type.getMemberScope(), collector); + } + + private static void validateReturnType(CallableDescriptor descriptor, DiagnosticCollector collector) { + validateType(descriptor, descriptor.getReturnType(), collector); + } + + private static void validateTypeParameters(DiagnosticCollector collector, List 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 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 static void validateTypes( + DeclarationDescriptor descriptor, + DiagnosticCollector collector, + Collection types + ) { + for (JetType type : types) { + validateType(descriptor, type, collector); + } + } + + private static void validateCallable(CallableDescriptor descriptor, DiagnosticCollector collector) { + validateReturnType(descriptor, collector); + validateTypeParameters(collector, descriptor.getTypeParameters()); + validateValueParameters(collector, descriptor.getValueParameters()); + } + + private static 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 void validateAccessor( + PropertyDescriptor descriptor, + DiagnosticCollector collector, + PropertyAccessorDescriptor accessor, + String name + ) { + // TODO + //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 visitNamespaceDescriptor( + NamespaceDescriptor descriptor, DiagnosticCollector collector + ) { + validateScope(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()); + return true; + } + + @Override + public Boolean visitClassDescriptor( + ClassDescriptor descriptor, DiagnosticCollector collector + ) { + validateTypeParameters(collector, descriptor.getTypeConstructor().getParameters()); + validateTypes(descriptor, collector, descriptor.getTypeConstructor().getSupertypes()); + + validateType(descriptor, descriptor.getDefaultType(), collector); + + validateScope(descriptor.getUnsubstitutedInnerClassesScope(), collector); + + List 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()); + } + } + + return true; + } + + @Override + public Boolean visitModuleDeclaration( + ModuleDescriptor descriptor, DiagnosticCollector collector + ) { + return true; + } + + @Override + public Boolean visitConstructorDescriptor( + ConstructorDescriptor constructorDescriptor, DiagnosticCollector collector + ) { + visitFunctionDescriptor(constructorDescriptor, collector); + + assertEquals(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) { + assertEquals(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()); + assertEquals(setter, collector, "setter parameter type", descriptor.getType(), setter.getValueParameters().get(0).getType()); + } + + return true; + } + + @Override + public Boolean visitValueParameterDescriptor( + ValueParameterDescriptor descriptor, DiagnosticCollector collector + ) { + visitVariableDescriptor(descriptor, collector); + return true; + } + + @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); + + if (!descriptor.getValue().exists()) { + report(collector, descriptor, "Receiver value does not exist: " + descriptor.getValue()); + } + return true; + } + + } + + private static class ScopeValidatorVisitor implements DeclarationDescriptorVisitor { + 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 JetScope scope, + @NotNull DeclarationDescriptor expected, + @Nullable DeclarationDescriptor found + ) { + if (found == null) { + report(expected, "Not found in " + scope); + } + if (expected != found) { + report(expected, "Lookup error in " + scope + ": " + found); + } + } + + private void assertFound( + @NotNull JetScope scope, + @NotNull DeclarationDescriptor expected, + @NotNull Collection found + ) { + if (!found.contains(expected)) { + report(expected, "Not found in " + scope + ": " + found); + } + } + + @Override + public Void visitNamespaceDescriptor( + NamespaceDescriptor descriptor, JetScope scope + ) { + assertFound(scope, descriptor, scope.getNamespace(descriptor.getName())); + return null; + } + + @Override + public Void visitVariableDescriptor( + VariableDescriptor descriptor, JetScope scope + ) { + assertFound(scope, descriptor, scope.getProperties(descriptor.getName())); + return null; + } + + @Override + public Void visitFunctionDescriptor( + FunctionDescriptor descriptor, JetScope scope + ) { + assertFound(scope, descriptor, scope.getFunctions(descriptor.getName())); + return null; + } + + @Override + public Void visitTypeParameterDescriptor( + TypeParameterDescriptor descriptor, JetScope scope + ) { + assertFound(scope, descriptor, scope.getClassifier(descriptor.getName())); + return null; + } + + @Override + public Void visitClassDescriptor( + ClassDescriptor descriptor, JetScope scope + ) { + if (descriptor.getKind().isObject()) { + assertFound(scope, descriptor, scope.getObjectDescriptor(descriptor.getName())); + } + else { + assertFound(scope, descriptor, scope.getClassifier(descriptor.getName())); + } + return null; + } + + @Override + public Void visitModuleDeclaration( + ModuleDescriptor descriptor, JetScope scope + ) { + report(descriptor, "Module found in scope: " + scope); + return null; + } + + @Override + public Void visitConstructorDescriptor( + ConstructorDescriptor descriptor, JetScope scope + ) { + report(descriptor, "Constructor found in scope: " + scope); + return null; + } + + @Override + public Void visitScriptDescriptor( + ScriptDescriptor descriptor, JetScope scope + ) { + report(descriptor, "Script found in scope: " + scope); + return null; + } + + @Override + public Void visitPropertyDescriptor( + PropertyDescriptor descriptor, JetScope scope + ) { + return visitVariableDescriptor(descriptor, scope); + } + + @Override + public Void visitValueParameterDescriptor( + ValueParameterDescriptor descriptor, JetScope scope + ) { + return visitVariableDescriptor(descriptor, scope); + } + + @Override + public Void visitPropertyGetterDescriptor( + PropertyGetterDescriptor descriptor, JetScope scope + ) { + report(descriptor, "Getter found in scope: " + scope); + return null; + } + + @Override + public Void visitPropertySetterDescriptor( + PropertySetterDescriptor descriptor, JetScope scope + ) { + report(descriptor, "Setter found in scope: " + scope); + return null; + } + + @Override + public Void visitReceiverParameterDescriptor( + ReceiverParameterDescriptor descriptor, JetScope scope + ) { + report(descriptor, "Receiver parameter found in scope: " + scope); + return null; + } + } + + public static class Diagnostic { + + private final DeclarationDescriptor descriptor; + private final String message; + private final Throwable stackTrace; + + private Diagnostic(@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 Diagnostic diagnostic) { + diagnostic.printStackTrace(System.err); + errorsFound = true; + } + + public void done() { + if (errorsFound) { + Assert.fail("Descriptor validation failed (see messages above)"); + } + } + } + +} diff --git a/compiler/tests/org/jetbrains/jet/test/util/RecursiveDescriptorProcessor.java b/compiler/tests/org/jetbrains/jet/test/util/RecursiveDescriptorProcessor.java new file mode 100644 index 00000000000..18e524e46bc --- /dev/null +++ b/compiler/tests/org/jetbrains/jet/test/util/RecursiveDescriptorProcessor.java @@ -0,0 +1,148 @@ +/* + * Copyright 2010-2013 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.jet.test.util; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.resolve.name.FqName; + +import java.util.Collection; +import java.util.Collections; + +public class RecursiveDescriptorProcessor { + public static boolean process( + @NotNull Collection descriptors, + D data, + @NotNull DeclarationDescriptorVisitor visitor + ) { + RecursiveVisitor recursive = new RecursiveVisitor(visitor); + for (DeclarationDescriptor descriptor : descriptors) { + if (!descriptor.accept(visitor, data)) { + return false; + } + descriptor.accept(recursive, data); + } + return true; + } + + public static boolean process( + @NotNull DeclarationDescriptor descriptor, + D data, + @NotNull DeclarationDescriptorVisitor visitor + ) { + return process(Collections.singletonList(descriptor), data, visitor); + } + + private static class RecursiveVisitor implements DeclarationDescriptorVisitor { + + private final DeclarationDescriptorVisitor worker; + + private RecursiveVisitor(@NotNull DeclarationDescriptorVisitor worker) { + this.worker = worker; + } + + private boolean doProcess(Collection descriptors, D data) { + return process(descriptors, data, worker); + } + + private boolean doProcess(@Nullable DeclarationDescriptor receiverParameter, D data) { + if (receiverParameter == null) { + return true; + } + return receiverParameter.accept(worker, data); + } + + private boolean processCallable(CallableDescriptor descriptor, D data) { + return doProcess(descriptor.getTypeParameters(), data) + && doProcess(descriptor.getReceiverParameter(), data) + && doProcess(descriptor.getValueParameters(), data); + } + + @Override + public Boolean visitNamespaceDescriptor(NamespaceDescriptor descriptor, D data) { + return doProcess(descriptor.getMemberScope().getAllDescriptors(), 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) + && doProcess(descriptor.getGetter(), data) + && doProcess(descriptor.getSetter(), data); + } + + @Override + public Boolean visitFunctionDescriptor(FunctionDescriptor descriptor, D data) { + return processCallable(descriptor, data); + } + + @Override + public Boolean visitTypeParameterDescriptor(TypeParameterDescriptor descriptor, D data) { + return true; + } + + @Override + public Boolean visitClassDescriptor(ClassDescriptor descriptor, D data) { + return doProcess(descriptor.getThisAsReceiverParameter(), data) + && doProcess(descriptor.getConstructors(), data) + && doProcess(descriptor.getTypeConstructor().getParameters(), data) + && doProcess(descriptor.getClassObjectDescriptor(), data) + && doProcess(descriptor.getDefaultType().getMemberScope().getObjectDescriptors(), data) + && doProcess(descriptor.getDefaultType().getMemberScope().getAllDescriptors(), data); + } + + @Override + public Boolean visitModuleDeclaration(ModuleDescriptor descriptor, D data) { + return doProcess(descriptor.getNamespace(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.getClassDescriptor(), 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 true; + } + } +}