diff --git a/compiler/testData/recursiveProcessor/declarations.kt b/compiler/testData/recursiveProcessor/declarations.kt new file mode 100644 index 00000000000..d50427ed64e --- /dev/null +++ b/compiler/testData/recursiveProcessor/declarations.kt @@ -0,0 +1,41 @@ +package test.innerTest + +fun T1.func(a: T1): T1 = a +val T2.prop: T2? = null +var propVar: Any? = null + +trait Trait { + fun traitFunc(): Unit {} + val traitProp: Any? +} + +abstract class Class : Trait { + fun classFunc(): Unit {} + val classProp: Any? = null + + class object { + fun classObjFunc(): Unit {} + val classObjProp: Any? = null + } +} + +object Object { + fun objFunc(): Unit {} + val objProp: Any? = null +} + +trait Outer { + trait NestedTrait { + fun nestedTraitFun() {} + } + + abstract class NestedClass { + class object { + fun nestedClassObjFunc(): Unit {} + } + } + + object Object { + fun nestedFunc(): Unit {} + } +} \ No newline at end of file diff --git a/compiler/testData/recursiveProcessor/declarations.txt b/compiler/testData/recursiveProcessor/declarations.txt new file mode 100644 index 00000000000..a64a5a01527 --- /dev/null +++ b/compiler/testData/recursiveProcessor/declarations.txt @@ -0,0 +1,56 @@ +.:PropertyGetterDescriptor +.():ConstructorDescriptor +.classObjFunc:SimpleFunctionDescriptor +.classObjProp:PropertyDescriptor +.this:ReceiverParameterDescriptor +:ClassDescriptor +.():ConstructorDescriptor +.nestedClassObjFunc:SimpleFunctionDescriptor +.this:ReceiverParameterDescriptor +:ClassDescriptor +:MutableValueParameterDescriptor +Class.:PropertyGetterDescriptor +Class.():ConstructorDescriptor +Class.classFunc:SimpleFunctionDescriptor +Class.classProp:PropertyDescriptor +Class.this:ReceiverParameterDescriptor +Class:ClassDescriptor +NestedClass.():ConstructorDescriptor +NestedClass.this:ReceiverParameterDescriptor +NestedClass:ClassDescriptor +NestedTrait.nestedTraitFun:SimpleFunctionDescriptor +NestedTrait.this:ReceiverParameterDescriptor +NestedTrait:ClassDescriptor +Object.():ConstructorDescriptor +Object.nestedFunc:SimpleFunctionDescriptor +Object.this:ReceiverParameterDescriptor +Object:ClassDescriptor +Outer.Object:PropertyDescriptor +Outer.this:ReceiverParameterDescriptor +Outer:ClassDescriptor +T1:TypeParameterDescriptor +T2:TypeParameterDescriptor +T3:TypeParameterDescriptor +T4:TypeParameterDescriptor +T4:TypeParameterDescriptor +Trait.:PropertyGetterDescriptor +Trait.this:ReceiverParameterDescriptor +Trait.traitFunc:SimpleFunctionDescriptor +Trait.traitProp:PropertyDescriptor +Trait:ClassDescriptor +a:MutableValueParameterDescriptor +fake Class.:PropertyGetterDescriptor +fake Class.traitFunc:SimpleFunctionDescriptor +fake Class.traitProp:PropertyDescriptor +func.this:ReceiverParameterDescriptor +innerTest.:PropertyGetterDescriptor +innerTest.:PropertyGetterDescriptor +innerTest.:PropertySetterDescriptor +innerTest.Object:PropertyDescriptor +innerTest.func:SimpleFunctionDescriptor +innerTest.prop:PropertyDescriptor +innerTest.propVar:PropertyDescriptor +innerTest:NamespaceDescriptor +prop.this:ReceiverParameterDescriptor +prop.this:ReceiverParameterDescriptor +test:NamespaceDescriptor diff --git a/compiler/tests/org/jetbrains/jet/test/util/RecursiveDescriptorProcessor.java b/compiler/tests/org/jetbrains/jet/test/util/RecursiveDescriptorProcessor.java index 18e524e46bc..db5c5ab5132 100644 --- a/compiler/tests/org/jetbrains/jet/test/util/RecursiveDescriptorProcessor.java +++ b/compiler/tests/org/jetbrains/jet/test/util/RecursiveDescriptorProcessor.java @@ -22,30 +22,15 @@ 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); + return descriptor.accept(new RecursiveVisitor(visitor), data); } private static class RecursiveVisitor implements DeclarationDescriptorVisitor { @@ -56,26 +41,34 @@ public class RecursiveDescriptorProcessor { this.worker = worker; } - private boolean doProcess(Collection descriptors, D data) { - return process(descriptors, data, worker); + private boolean visitChildren(Collection descriptors, D data) { + for (DeclarationDescriptor descriptor : descriptors) { + if (!descriptor.accept(this, data)) return false; + } + return true; } - private boolean doProcess(@Nullable DeclarationDescriptor receiverParameter, D data) { - if (receiverParameter == null) { - return true; - } - return receiverParameter.accept(worker, data); + 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 doProcess(descriptor.getTypeParameters(), data) - && doProcess(descriptor.getReceiverParameter(), data) - && doProcess(descriptor.getValueParameters(), data); + return applyWorker(descriptor, data) + && visitChildren(descriptor.getTypeParameters(), data) + && visitChildren(descriptor.getReceiverParameter(), data) + && visitChildren(descriptor.getValueParameters(), data); } @Override public Boolean visitNamespaceDescriptor(NamespaceDescriptor descriptor, D data) { - return doProcess(descriptor.getMemberScope().getAllDescriptors(), data); + return applyWorker(descriptor, data) + && visitChildren(descriptor.getMemberScope().getAllDescriptors(), data); } @Override @@ -86,8 +79,8 @@ public class RecursiveDescriptorProcessor { @Override public Boolean visitPropertyDescriptor(PropertyDescriptor descriptor, D data) { return processCallable(descriptor, data) - && doProcess(descriptor.getGetter(), data) - && doProcess(descriptor.getSetter(), data); + && visitChildren(descriptor.getGetter(), data) + && visitChildren(descriptor.getSetter(), data); } @Override @@ -97,22 +90,24 @@ public class RecursiveDescriptorProcessor { @Override public Boolean visitTypeParameterDescriptor(TypeParameterDescriptor descriptor, D data) { - return true; + return applyWorker(descriptor, data); } @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); + return applyWorker(descriptor, data) + && visitChildren(descriptor.getThisAsReceiverParameter(), data) + && visitChildren(descriptor.getConstructors(), data) + && visitChildren(descriptor.getTypeConstructor().getParameters(), data) + && visitChildren(descriptor.getClassObjectDescriptor(), data) + && visitChildren(descriptor.getDefaultType().getMemberScope().getObjectDescriptors(), data) + && visitChildren(descriptor.getDefaultType().getMemberScope().getAllDescriptors(), data); } @Override public Boolean visitModuleDeclaration(ModuleDescriptor descriptor, D data) { - return doProcess(descriptor.getNamespace(FqName.ROOT), data); + return applyWorker(descriptor, data) + && visitChildren(descriptor.getNamespace(FqName.ROOT), data); } @Override @@ -142,7 +137,7 @@ public class RecursiveDescriptorProcessor { @Override public Boolean visitReceiverParameterDescriptor(ReceiverParameterDescriptor descriptor, D data) { - return true; + return applyWorker(descriptor, data); } } } diff --git a/compiler/tests/org/jetbrains/jet/test/util/RecursiveDescriptorProcessorTest.java b/compiler/tests/org/jetbrains/jet/test/util/RecursiveDescriptorProcessorTest.java new file mode 100644 index 00000000000..842d68ffb3e --- /dev/null +++ b/compiler/tests/org/jetbrains/jet/test/util/RecursiveDescriptorProcessorTest.java @@ -0,0 +1,185 @@ +/* + * 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 com.intellij.openapi.util.io.FileUtil; +import org.jetbrains.jet.JetTestUtils; +import org.jetbrains.jet.analyzer.AnalyzeExhaust; +import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.psi.JetFile; +import org.jetbrains.jet.lang.resolve.lazy.KotlinTestWithEnvironment; +import org.jetbrains.jet.lang.resolve.name.FqName; +import org.jetbrains.jet.lang.resolve.name.Name; +import org.jetbrains.jet.utils.Printer; + +import java.io.File; +import java.util.Collections; +import java.util.List; + +public class RecursiveDescriptorProcessorTest extends KotlinTestWithEnvironment { + @Override + protected JetCoreEnvironment createEnvironment() { + return JetTestUtils.createEnvironmentWithMockJdkAndIdeaAnnotations(getTestRootDisposable()); + } + + public void testRecursive() throws Exception { + File ktFile = new File("compiler/testData/recursiveProcessor/declarations.kt"); + File txtFile = new File("compiler/testData/recursiveProcessor/declarations.txt"); + String text = FileUtil.loadFile(ktFile); + JetFile jetFile = JetTestUtils.createFile("declarations.kt", text, getEnvironment().getProject()); + AnalyzeExhaust exhaust = JetTestUtils.analyzeFile(jetFile); + NamespaceDescriptor testPackage = exhaust.getModuleDescriptor().getNamespace(FqName.topLevel(Name.identifier("test"))); + assert testPackage != null; + + List descriptors = recursivelyCollectDescriptors(testPackage); + + StringBuilder builder = new StringBuilder(); + Printer p = new Printer(builder); + for (String descriptor : descriptors) { + p.println(descriptor); + } + String actualText = builder.toString(); + + if (!txtFile.exists()) { + FileUtil.writeToFile(txtFile, actualText); + fail("Test data file did not exist and was created from the results of the test: " + txtFile); + } + + assertEquals(FileUtil.loadFile(txtFile), actualText); + } + + private static Class closestInterface(Class aClass) { + if (aClass == null) return null; + if (aClass.isInterface()) return aClass; + + Class[] interfaces = aClass.getInterfaces(); + if (interfaces.length > 0) return interfaces[0]; + + return closestInterface(aClass.getSuperclass()); + } + + private static List recursivelyCollectDescriptors(NamespaceDescriptor testPackage) { + final List lines = Lists.newArrayList(); + RecursiveDescriptorProcessor.process(testPackage, null, new DeclarationDescriptorVisitor() { + + private void add(DeclarationDescriptor descriptor) { + add(descriptor.getName().asString(), descriptor); + } + + private void add(String name, DeclarationDescriptor descriptor) { + lines.add(name + ":" + closestInterface(descriptor.getClass()).getSimpleName()); + } + + private void addCallable(CallableMemberDescriptor descriptor) { + String prefix = descriptor.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE ? "fake " : ""; + add(prefix + descriptor.getContainingDeclaration().getName() + "." + descriptor.getName(), descriptor); + } + + @Override + public Boolean visitNamespaceDescriptor(NamespaceDescriptor descriptor, Void data) { + add(descriptor); + return true; + } + + @Override + public Boolean visitVariableDescriptor(VariableDescriptor descriptor, Void data) { + add(descriptor); + return true; + } + + @Override + public Boolean visitFunctionDescriptor(FunctionDescriptor descriptor, Void data) { + addCallable(descriptor); + return true; + } + + @Override + public Boolean visitTypeParameterDescriptor(TypeParameterDescriptor descriptor, Void data) { + add(descriptor); + return true; + } + + @Override + public Boolean visitClassDescriptor(ClassDescriptor descriptor, Void data) { + add(descriptor); + return true; + } + + @Override + public Boolean visitModuleDeclaration(ModuleDescriptor descriptor, Void data) { + add(descriptor); + return true; + } + + @Override + public Boolean visitConstructorDescriptor( + ConstructorDescriptor constructorDescriptor, Void data + ) { + add(constructorDescriptor.getContainingDeclaration().getName() + ".()", constructorDescriptor); + return true; + } + + @Override + public Boolean visitScriptDescriptor(ScriptDescriptor scriptDescriptor, Void data) { + add(scriptDescriptor); + return true; + } + + @Override + public Boolean visitPropertyDescriptor(PropertyDescriptor descriptor, Void data) { + addCallable(descriptor); + return true; + } + + @Override + public Boolean visitValueParameterDescriptor( + ValueParameterDescriptor descriptor, Void data + ) { + add(descriptor); + return true; + } + + @Override + public Boolean visitPropertyGetterDescriptor( + PropertyGetterDescriptor descriptor, Void data + ) { + addCallable(descriptor); + return true; + } + + @Override + public Boolean visitPropertySetterDescriptor( + PropertySetterDescriptor descriptor, Void data + ) { + addCallable(descriptor); + return true; + } + + @Override + public Boolean visitReceiverParameterDescriptor( + ReceiverParameterDescriptor descriptor, Void data + ) { + add(descriptor.getContainingDeclaration().getName() + ".this", descriptor); + return true; + } + }); + Collections.sort(lines); + return lines; + } +}