diff --git a/.idea/inspectionProfiles/idea_default.xml b/.idea/inspectionProfiles/idea_default.xml index 23bae163cd7..6c2f8ad45ac 100644 --- a/.idea/inspectionProfiles/idea_default.xml +++ b/.idea/inspectionProfiles/idea_default.xml @@ -410,6 +410,9 @@ diff --git a/.idea/runConfigurations/Js_backend_tests.xml b/.idea/runConfigurations/Js_backend_tests.xml index f743bf7dde6..95f27eae686 100644 --- a/.idea/runConfigurations/Js_backend_tests.xml +++ b/.idea/runConfigurations/Js_backend_tests.xml @@ -26,8 +26,6 @@ - - + \ No newline at end of file diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java index 18edab436a2..5ae0c455cbf 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java @@ -198,7 +198,7 @@ public class ClosureCodegen extends ObjectOrClosureCodegen { private Type generateBody(FunctionDescriptor funDescriptor, ClassBuilder cv, JetDeclarationWithBody body) { ClassDescriptor function = state.getInjector().getJetTypeMapper().getClosureAnnotator().classDescriptorForFunctionDescriptor(funDescriptor, name); - final CodegenContext.ClosureContext closureContext = context.intoClosure( + final CodegenContexts.ClosureContext closureContext = context.intoClosure( funDescriptor, function, name.getInternalName(), this, state.getInjector().getJetTypeMapper()); FunctionCodegen fc = new FunctionCodegen(closureContext, cv, state); JvmMethodSignature jvmMethodSignature = invokeSignature(funDescriptor); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java index d387a0f20b4..11969ba40d7 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java @@ -35,25 +35,6 @@ import java.util.LinkedHashMap; * @author alex.tkachman */ public abstract class CodegenContext { - public static final CodegenContext STATIC = new CodegenContext(null, OwnerKind.NAMESPACE, null, null) { - @Override - protected ClassDescriptor getThisDescriptor() { - return null; - } - - @Override - public boolean isStatic() { - return true; - } - - @Override - public String toString() { - return "ROOT"; - } - }; - - protected static final StackValue local0 = StackValue.local(0, JetTypeMapper.TYPE_OBJECT); - protected static final StackValue local1 = StackValue.local(1, JetTypeMapper.TYPE_OBJECT); private final DeclarationDescriptor contextType; @@ -121,31 +102,31 @@ public abstract class CodegenContext { } public CodegenContext intoNamespace(NamespaceDescriptor descriptor) { - return new NamespaceContext(descriptor, this); + return new CodegenContexts.NamespaceContext(descriptor, this); } public CodegenContext intoClass(ClassDescriptor descriptor, OwnerKind kind, JetTypeMapper typeMapper) { - return new ClassContext(descriptor, kind, this, typeMapper); + return new CodegenContexts.ClassContext(descriptor, kind, this, typeMapper); } public CodegenContext intoAnonymousClass(@NotNull ObjectOrClosureCodegen closure, ClassDescriptor descriptor, OwnerKind kind, JetTypeMapper typeMapper) { - return new AnonymousClassContext(descriptor, kind, this, closure, typeMapper); + return new CodegenContexts.AnonymousClassContext(descriptor, kind, this, closure, typeMapper); } - public MethodContext intoFunction(FunctionDescriptor descriptor) { - return new MethodContext(descriptor, getContextKind(), this); + public CodegenContexts.MethodContext intoFunction(FunctionDescriptor descriptor) { + return new CodegenContexts.MethodContext(descriptor, getContextKind(), this); } - public ConstructorContext intoConstructor(ConstructorDescriptor descriptor, JetTypeMapper typeMapper) { + public CodegenContexts.ConstructorContext intoConstructor(ConstructorDescriptor descriptor, JetTypeMapper typeMapper) { if(descriptor == null) { descriptor = new ConstructorDescriptorImpl(getThisDescriptor(), Collections.emptyList(), true) .initialize(Collections.emptyList(), Collections.emptyList(), Visibilities.PUBLIC); } - return new ConstructorContext(descriptor, getContextKind(), this, typeMapper); + return new CodegenContexts.ConstructorContext(descriptor, getContextKind(), this, typeMapper); } - public ClosureContext intoClosure(FunctionDescriptor funDescriptor, ClassDescriptor classDescriptor, String internalClassName, ClosureCodegen closureCodegen, JetTypeMapper typeMapper) { - return new ClosureContext(funDescriptor, classDescriptor, this, closureCodegen, internalClassName, typeMapper); + public CodegenContexts.ClosureContext intoClosure(FunctionDescriptor funDescriptor, ClassDescriptor classDescriptor, String internalClassName, ClosureCodegen closureCodegen, JetTypeMapper typeMapper) { + return new CodegenContexts.ClosureContext(funDescriptor, classDescriptor, this, closureCodegen, internalClassName, typeMapper); } public FrameMap prepareFrame(JetTypeMapper mapper) { @@ -190,7 +171,7 @@ public abstract class CodegenContext { } public int getTypeInfoConstantIndex(JetType type) { - if (parentContext != STATIC) { return parentContext.getTypeInfoConstantIndex(type); } + if (parentContext != CodegenContexts.STATIC) { return parentContext.getTypeInfoConstantIndex(type); } if(typeInfoConstants == null) { typeInfoConstants = new LinkedHashMap(); @@ -242,7 +223,7 @@ public abstract class CodegenContext { CallableMemberDescriptor.Kind.DECLARATION ); JetType receiverType = pd.getReceiverParameter().exists() ? pd.getReceiverParameter().getType() : null; - myAccessor.setType(pd.getType(), Collections.emptyList(), pd.getExpectedThisObject(), receiverType); + myAccessor.setType(pd.getType(), Collections.emptyList(), pd.getExpectedThisObject(), receiverType); PropertyGetterDescriptor pgd = new PropertyGetterDescriptor( myAccessor, Collections.emptyList(), myAccessor.getModality(), @@ -280,174 +261,4 @@ public abstract class CodegenContext { this.accessors.putAll(accessors); } } - - public abstract static class ReceiverContext extends CodegenContext { - final CallableDescriptor receiverDescriptor; - - public ReceiverContext(CallableDescriptor contextType, OwnerKind contextKind, CodegenContext parentContext, @Nullable ObjectOrClosureCodegen closureCodegen) { - super(contextType, contextKind, parentContext, closureCodegen); - receiverDescriptor = contextType.getReceiverParameter().exists() ? contextType : null; - } - - @Override - protected CallableDescriptor getReceiverDescriptor() { - return receiverDescriptor; - } - } - - public static class MethodContext extends ReceiverContext { - public MethodContext(FunctionDescriptor contextType, OwnerKind contextKind, CodegenContext parentContext) { - super(contextType instanceof PropertyAccessorDescriptor ? ((PropertyAccessorDescriptor)contextType).getCorrespondingProperty() : contextType, contextKind, parentContext, null); - } - - @Override - protected ClassDescriptor getThisDescriptor() { - return getParentContext().getThisDescriptor(); - } - - public StackValue lookupInContext(DeclarationDescriptor d, InstructionAdapter v, StackValue result) { - return getParentContext().lookupInContext(d, v, result); - } - - public Type enclosingClassType(JetTypeMapper typeMapper) { - return getParentContext().enclosingClassType(typeMapper); - } - - @Override - public boolean isStatic() { - return getParentContext().isStatic(); - } - - protected StackValue getOuterExpression(StackValue prefix) { - return getParentContext().getOuterExpression(prefix); - } - - @Override - public String toString() { - return "Method: " + getContextDescriptor(); - } - } - - public static class ConstructorContext extends MethodContext { - public ConstructorContext(ConstructorDescriptor contextType, OwnerKind kind, CodegenContext parent, JetTypeMapper typeMapper) { - super(contextType, kind, parent); - - final Type type = enclosingClassType(typeMapper); - outerExpression = type != null - ? local1 - : null; - } - - protected StackValue getOuterExpression(StackValue prefix) { - return outerExpression; - } - - @Override - public String toString() { - return "Constructor: " + getContextDescriptor().getName(); - } - } - - public static class ClassContext extends CodegenContext { - public ClassContext(ClassDescriptor contextType, OwnerKind contextKind, CodegenContext parentContext, JetTypeMapper typeMapper) { - super(contextType, contextKind, parentContext, null); - - final Type type = enclosingClassType(typeMapper); - outerExpression = type != null - ? StackValue.field(type, typeMapper.getFQName(contextType), "this$0", false) - : null; - } - - @Override - protected ClassDescriptor getThisDescriptor() { - return (ClassDescriptor) getContextDescriptor(); - } - - @Override - public boolean isStatic() { - return false; - } - } - - public static class AnonymousClassContext extends CodegenContext { - public AnonymousClassContext(ClassDescriptor contextType, OwnerKind contextKind, CodegenContext parentContext, @NotNull ObjectOrClosureCodegen closure, JetTypeMapper typeMapper) { - super(contextType, contextKind, parentContext, closure); - - final Type type = enclosingClassType(typeMapper); - Type owner = closure.state.getInjector().getJetTypeMapper().mapType(contextType.getDefaultType(), MapTypeMode.IMPL); - outerExpression = type != null - ? StackValue.field(type, owner.getInternalName(), "this$0", false) - : null; - } - - @Override - protected ClassDescriptor getThisDescriptor() { - return (ClassDescriptor) getContextDescriptor(); - } - - @Override - public boolean isStatic() { - return false; - } - - @Override - public String toString() { - return "Anonymous: " + getThisDescriptor(); - } - } - - public static class ClosureContext extends ReceiverContext { - private ClassDescriptor classDescriptor; - - public ClosureContext(FunctionDescriptor contextType, ClassDescriptor classDescriptor, CodegenContext parentContext, @NotNull ObjectOrClosureCodegen closureCodegen, String internalClassName, JetTypeMapper typeMapper) { - super(contextType, OwnerKind.IMPLEMENTATION, parentContext, closureCodegen); - this.classDescriptor = classDescriptor; - - final Type type = enclosingClassType(typeMapper); - outerExpression = type != null - ? StackValue.field(type, internalClassName, "this$0", false) - : null; - } - - @Override - protected ClassDescriptor getThisDescriptor() { - return classDescriptor; - } - - @Override - public DeclarationDescriptor getContextDescriptor() { - return classDescriptor; - } - - @Override - public boolean isStatic() { - return false; - } - - @Override - public String toString() { - return "Closure: " + classDescriptor; - } - } - - public static class NamespaceContext extends CodegenContext { - public NamespaceContext(NamespaceDescriptor contextType, CodegenContext parent) { - super(contextType, OwnerKind.NAMESPACE, parent, null); - } - - @Override - protected ClassDescriptor getThisDescriptor() { - return null; - } - - @Override - public boolean isStatic() { - return true; - } - - @Override - public String toString() { - return "Namespace: " + getContextDescriptor().getName(); - } - } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContexts.java b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContexts.java new file mode 100644 index 00000000000..283d26ff222 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContexts.java @@ -0,0 +1,223 @@ +/* + * Copyright 2010-2012 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.codegen; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.CallableDescriptor; +import org.jetbrains.jet.lang.descriptors.ClassDescriptor; +import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; +import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; +import org.jetbrains.jet.lang.descriptors.PropertyAccessorDescriptor; +import org.objectweb.asm.Type; +import org.objectweb.asm.commons.InstructionAdapter; + +/** + * @author Stepan Koltsov + */ +public class CodegenContexts { + public static final CodegenContext STATIC = new CodegenContext(null, OwnerKind.NAMESPACE, null, null) { + @Override + protected ClassDescriptor getThisDescriptor() { + return null; + } + + @Override + public boolean isStatic() { + return true; + } + + @Override + public String toString() { + return "ROOT"; + } + }; + protected static final StackValue local0 = StackValue.local(0, JetTypeMapper.TYPE_OBJECT); + protected static final StackValue local1 = StackValue.local(1, JetTypeMapper.TYPE_OBJECT); + + public abstract static class ReceiverContext extends CodegenContext { + final CallableDescriptor receiverDescriptor; + + public ReceiverContext(CallableDescriptor contextType, OwnerKind contextKind, CodegenContext parentContext, @Nullable ObjectOrClosureCodegen closureCodegen) { + super(contextType, contextKind, parentContext, closureCodegen); + receiverDescriptor = contextType.getReceiverParameter().exists() ? contextType : null; + } + + @Override + protected CallableDescriptor getReceiverDescriptor() { + return receiverDescriptor; + } + } + + public static class MethodContext extends ReceiverContext { + public MethodContext(FunctionDescriptor contextType, OwnerKind contextKind, CodegenContext parentContext) { + super(contextType instanceof PropertyAccessorDescriptor ? ((PropertyAccessorDescriptor)contextType).getCorrespondingProperty() : contextType, contextKind, parentContext, null); + } + + @Override + protected ClassDescriptor getThisDescriptor() { + return getParentContext().getThisDescriptor(); + } + + public StackValue lookupInContext(DeclarationDescriptor d, InstructionAdapter v, StackValue result) { + return getParentContext().lookupInContext(d, v, result); + } + + public Type enclosingClassType(JetTypeMapper typeMapper) { + return getParentContext().enclosingClassType(typeMapper); + } + + @Override + public boolean isStatic() { + return getParentContext().isStatic(); + } + + protected StackValue getOuterExpression(StackValue prefix) { + return getParentContext().getOuterExpression(prefix); + } + + @Override + public String toString() { + return "Method: " + getContextDescriptor(); + } + } + + public static class ConstructorContext extends MethodContext { + public ConstructorContext(ConstructorDescriptor contextType, OwnerKind kind, CodegenContext parent, JetTypeMapper typeMapper) { + super(contextType, kind, parent); + + final Type type = enclosingClassType(typeMapper); + outerExpression = type != null + ? local1 + : null; + } + + protected StackValue getOuterExpression(StackValue prefix) { + return outerExpression; + } + + @Override + public String toString() { + return "Constructor: " + getContextDescriptor().getName(); + } + } + + public static class ClassContext extends CodegenContext { + public ClassContext(ClassDescriptor contextType, OwnerKind contextKind, CodegenContext parentContext, JetTypeMapper typeMapper) { + super(contextType, contextKind, parentContext, null); + + final Type type = enclosingClassType(typeMapper); + outerExpression = type != null + ? StackValue.field(type, typeMapper.getFQName(contextType), "this$0", false) + : null; + } + + @Override + protected ClassDescriptor getThisDescriptor() { + return (ClassDescriptor) getContextDescriptor(); + } + + @Override + public boolean isStatic() { + return false; + } + } + + public static class AnonymousClassContext extends CodegenContext { + public AnonymousClassContext(ClassDescriptor contextType, OwnerKind contextKind, CodegenContext parentContext, @NotNull ObjectOrClosureCodegen closure, JetTypeMapper typeMapper) { + super(contextType, contextKind, parentContext, closure); + + final Type type = enclosingClassType(typeMapper); + Type owner = closure.state.getInjector().getJetTypeMapper().mapType(contextType.getDefaultType(), MapTypeMode.IMPL); + outerExpression = type != null + ? StackValue.field(type, owner.getInternalName(), "this$0", false) + : null; + } + + @Override + protected ClassDescriptor getThisDescriptor() { + return (ClassDescriptor) getContextDescriptor(); + } + + @Override + public boolean isStatic() { + return false; + } + + @Override + public String toString() { + return "Anonymous: " + getThisDescriptor(); + } + } + + public static class ClosureContext extends ReceiverContext { + private ClassDescriptor classDescriptor; + + public ClosureContext(FunctionDescriptor contextType, ClassDescriptor classDescriptor, CodegenContext parentContext, @NotNull ObjectOrClosureCodegen closureCodegen, String internalClassName, JetTypeMapper typeMapper) { + super(contextType, OwnerKind.IMPLEMENTATION, parentContext, closureCodegen); + this.classDescriptor = classDescriptor; + + final Type type = enclosingClassType(typeMapper); + outerExpression = type != null + ? StackValue.field(type, internalClassName, "this$0", false) + : null; + } + + @Override + protected ClassDescriptor getThisDescriptor() { + return classDescriptor; + } + + @Override + public DeclarationDescriptor getContextDescriptor() { + return classDescriptor; + } + + @Override + public boolean isStatic() { + return false; + } + + @Override + public String toString() { + return "Closure: " + classDescriptor; + } + } + + public static class NamespaceContext extends CodegenContext { + public NamespaceContext(NamespaceDescriptor contextType, CodegenContext parent) { + super(contextType, OwnerKind.NAMESPACE, parent, null); + } + + @Override + protected ClassDescriptor getThisDescriptor() { + return null; + } + + @Override + public boolean isStatic() { + return true; + } + + @Override + public String toString() { + return "Namespace: " + getContextDescriptor().getName(); + } + } +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java index caaf653c39b..be95711e65a 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java @@ -54,7 +54,7 @@ public class CodegenUtil { invokeDescriptor.initialize(fd.getReceiverParameter().exists() ? fd.getReceiverParameter().getType() : null, fd.getExpectedThisObject(), - Collections.emptyList(), + Collections.emptyList(), fd.getValueParameters(), fd.getReturnType(), Modality.FINAL, diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index fb370463936..9890c1183de 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -1093,7 +1093,7 @@ public class ExpressionCodegen extends JetVisitor { } } - if (descriptor instanceof TypeParameterDescriptor) { + if (descriptor instanceof TypeParameterDescriptorImpl) { TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) descriptor; v.invokevirtual("jet/TypeInfo", "getClassObject", "()Ljava/lang/Object;"); v.checkcast(asmType(typeParameterDescriptor.getClassObjectType())); @@ -1162,7 +1162,7 @@ public class ExpressionCodegen extends JetVisitor { boolean isStatic = containingDeclaration instanceof NamespaceDescriptor; propertyDescriptor = propertyDescriptor.getOriginal(); boolean isInsideClass = ((containingDeclaration == context.getThisDescriptor()) || - (context.getParentContext() instanceof CodegenContext.NamespaceContext) && context.getParentContext().getContextDescriptor() == containingDeclaration) + (context.getParentContext() instanceof CodegenContexts.NamespaceContext) && context.getParentContext().getContextDescriptor() == containingDeclaration) && contextKind() != OwnerKind.TRAIT_IMPL; Method getter; Method setter; @@ -1438,8 +1438,8 @@ public class ExpressionCodegen extends JetVisitor { } private StackValue generateReceiver(DeclarationDescriptor provided) { - assert context instanceof CodegenContext.ReceiverContext; - CodegenContext.ReceiverContext cur = (CodegenContext.ReceiverContext) context; + assert context instanceof CodegenContexts.ReceiverContext; + CodegenContexts.ReceiverContext cur = (CodegenContexts.ReceiverContext) context; if (cur.getReceiverDescriptor() == provided) { StackValue result = cur.getReceiverExpression(typeMapper); return castToRequiredTypeOfInterfaceIfNeeded(result, provided, null); @@ -1458,7 +1458,7 @@ public class ExpressionCodegen extends JetVisitor { cur = context; StackValue result = StackValue.local(0, TYPE_OBJECT); while (cur != null) { - if(cur instanceof CodegenContext.MethodContext && !(cur instanceof CodegenContext.ConstructorContext)) + if(cur instanceof CodegenContexts.MethodContext && !(cur instanceof CodegenContexts.ConstructorContext)) cur = cur.getParentContext(); if (DescriptorUtils.isSubclass(cur.getThisDescriptor(), calleeContainingClass)) { @@ -1474,7 +1474,7 @@ public class ExpressionCodegen extends JetVisitor { result = cur.getOuterExpression(result); - if(cur instanceof CodegenContext.ConstructorContext) { + if(cur instanceof CodegenContexts.ConstructorContext) { cur = cur.getParentContext(); } cur = cur.getParentContext(); @@ -2614,7 +2614,7 @@ If finally block is present, its last expression is the value of try expression. JetExpression left = expression.getLeft(); JetType leftType = bindingContext.get(BindingContext.EXPRESSION_TYPE, left); DeclarationDescriptor descriptor = rightType.getConstructor().getDeclarationDescriptor(); - if (descriptor instanceof ClassDescriptor || descriptor instanceof TypeParameterDescriptor) { + if (descriptor instanceof ClassDescriptor || descriptor instanceof TypeParameterDescriptorImpl) { StackValue value = genQualified(receiver, left); value.put(JetTypeMapper.boxType(value.type), v); assert leftType != null; diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java index 4a3d6788223..287328ea27a 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java @@ -69,7 +69,7 @@ public class FunctionCodegen { JvmMethodSignature jvmMethod, boolean needJetAnnotations, @Nullable String propertyTypeSignature, FunctionDescriptor functionDescriptor) { - CodegenContext.MethodContext funContext = owner.intoFunction(functionDescriptor); + CodegenContexts.MethodContext funContext = owner.intoFunction(functionDescriptor); final JetExpression bodyExpression = f.getBodyExpression(); generatedMethod(bodyExpression, jvmMethod, needJetAnnotations, propertyTypeSignature, funContext, functionDescriptor, f); @@ -78,7 +78,7 @@ public class FunctionCodegen { private void generatedMethod(JetExpression bodyExpressions, JvmMethodSignature jvmSignature, boolean needJetAnnotations, @Nullable String propertyTypeSignature, - CodegenContext.MethodContext context, + CodegenContexts.MethodContext context, FunctionDescriptor functionDescriptor, JetDeclarationWithBody fun ) @@ -301,7 +301,7 @@ public class FunctionCodegen { } } - static void generateDefaultIfNeeded(CodegenContext.MethodContext owner, GenerationState state, ClassBuilder v, Method jvmSignature, @Nullable FunctionDescriptor functionDescriptor, OwnerKind kind) { + static void generateDefaultIfNeeded(CodegenContexts.MethodContext owner, GenerationState state, ClassBuilder v, Method jvmSignature, @Nullable FunctionDescriptor functionDescriptor, OwnerKind kind) { DeclarationDescriptor contextClass = owner.getContextDescriptor().getContainingDeclaration(); if(kind != OwnerKind.TRAIT_IMPL) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index 9d0452be3f3..3d90db50b95 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -449,7 +449,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { ConstructorDescriptor constructorDescriptor = bindingContext.get(BindingContext.CONSTRUCTOR, myClass); - CodegenContext.ConstructorContext constructorContext = context.intoConstructor(constructorDescriptor, typeMapper); + CodegenContexts.ConstructorContext constructorContext = context.intoConstructor(constructorDescriptor, typeMapper); JvmMethodSignature constructorMethod; CallableMethod callableMethod; diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java index d1b3807da64..71bc4f14ec5 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -463,7 +463,7 @@ public class JetTypeMapper { return asmType; } - if (descriptor instanceof TypeParameterDescriptor) { + if (descriptor instanceof TypeParameterDescriptorImpl) { Type type = mapType(((TypeParameterDescriptor) descriptor).getUpperBoundsAsType(), kind); if (signatureVisitor != null) { @@ -722,7 +722,7 @@ public class JetTypeMapper { signatureVisitor.writeInterfaceBoundEnd(); } } - if (jetType.getConstructor().getDeclarationDescriptor() instanceof TypeParameterDescriptor) { + if (jetType.getConstructor().getDeclarationDescriptor() instanceof TypeParameterDescriptorImpl) { signatureVisitor.writeInterfaceBound(); mapType(jetType, signatureVisitor, MapTypeMode.TYPE_PARAMETER); signatureVisitor.writeInterfaceBoundEnd(); @@ -966,7 +966,7 @@ public class JetTypeMapper { public boolean isGenericsArray(JetType type) { DeclarationDescriptor declarationDescriptor = type.getConstructor().getDeclarationDescriptor(); - if(declarationDescriptor instanceof TypeParameterDescriptor) + if(declarationDescriptor instanceof TypeParameterDescriptorImpl) return true; if(standardLibrary.getArray().equals(declarationDescriptor)) diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java index fe0faeec34e..53348ac9506 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java @@ -23,7 +23,6 @@ import org.jetbrains.jet.lang.descriptors.PropertyDescriptor; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.name.FqName; -import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver; import org.jetbrains.jet.lang.resolve.java.JvmAbi; import org.jetbrains.jet.lang.resolve.java.JvmClassName; import org.objectweb.asm.MethodVisitor; @@ -57,7 +56,7 @@ public class NamespaceCodegen { public void generate(JetFile file) { NamespaceDescriptor descriptor = state.getBindingContext().get(BindingContext.FILE_TO_NAMESPACE, file); - final CodegenContext context = CodegenContext.STATIC.intoNamespace(descriptor); + final CodegenContext context = CodegenContexts.STATIC.intoNamespace(descriptor); final FunctionCodegen functionCodegen = new FunctionCodegen(context, v, state); final PropertyCodegen propertyCodegen = new PropertyCodegen(context, v, functionCodegen, state); @@ -100,7 +99,7 @@ public class NamespaceCodegen { mv.visitCode(); FrameMap frameMap = new FrameMap(); - ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, CodegenContext.STATIC, state); + ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, CodegenContexts.STATIC, state); for (JetDeclaration declaration : namespace.getDeclarations()) { if (declaration instanceof JetProperty) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ObjectOrClosureCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ObjectOrClosureCodegen.java index a670be29554..e0666f20af1 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ObjectOrClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ObjectOrClosureCodegen.java @@ -106,9 +106,9 @@ public class ObjectOrClosureCodegen { FunctionDescriptor fd = (FunctionDescriptor) d; // we generate method - assert context instanceof CodegenContext.ReceiverContext; + assert context instanceof CodegenContexts.ReceiverContext; - CodegenContext.ReceiverContext fcontext = (CodegenContext.ReceiverContext) context; + CodegenContexts.ReceiverContext fcontext = (CodegenContexts.ReceiverContext) context; if(fcontext.getReceiverDescriptor() != fd) return null; diff --git a/compiler/cli/src/org/jetbrains/jet/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.java b/compiler/cli/src/org/jetbrains/jet/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.java index 433574fa0ac..f5077050bb4 100644 --- a/compiler/cli/src/org/jetbrains/jet/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.java +++ b/compiler/cli/src/org/jetbrains/jet/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.java @@ -34,7 +34,6 @@ import org.jetbrains.jet.codegen.*; import org.jetbrains.jet.cli.common.messages.AnalyzerWithCompilerReport; import org.jetbrains.jet.cli.common.messages.CompilerMessageLocation; import org.jetbrains.jet.cli.common.messages.CompilerMessageSeverity; -import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.psi.JetPsiUtil; import org.jetbrains.jet.lang.resolve.name.FqName; @@ -246,7 +245,6 @@ public class KotlinToJVMBytecodeCompiler { public AnalyzeExhaust invoke() { return AnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration( environment.getProject(), environment.getSourceFiles(), filesToAnalyzeCompletely, - JetControlFlowDataTraceFactory.EMPTY, configuration.getEnvironment().getCompilerDependencies()); } }, environment.getSourceFiles() diff --git a/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJvm.java b/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJvm.java index 5f98e0cdbbe..fa918fa82e8 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJvm.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJvm.java @@ -17,16 +17,42 @@ package org.jetbrains.jet.di; +import org.jetbrains.jet.lang.resolve.TopDownAnalyzer; +import org.jetbrains.jet.lang.resolve.TopDownAnalysisContext; +import org.jetbrains.jet.lang.resolve.BodyResolver; +import org.jetbrains.jet.lang.resolve.ControlFlowAnalyzer; +import org.jetbrains.jet.lang.resolve.DeclarationsChecker; +import org.jetbrains.jet.lang.resolve.DescriptorResolver; import com.intellij.openapi.project.Project; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; +import org.jetbrains.jet.lang.resolve.TopDownAnalysisParameters; +import org.jetbrains.jet.lang.resolve.ObservableBindingTrace; import org.jetbrains.jet.lang.descriptors.ModuleDescriptor; -import org.jetbrains.jet.lang.resolve.*; +import org.jetbrains.jet.lang.resolve.java.CompilerDependencies; +import org.jetbrains.jet.lang.resolve.java.CompilerSpecialMode; +import org.jetbrains.jet.lang.resolve.java.JavaBridgeConfiguration; +import org.jetbrains.jet.lang.resolve.java.PsiClassFinderForJvm; +import org.jetbrains.jet.lang.resolve.DeclarationResolver; +import org.jetbrains.jet.lang.resolve.AnnotationResolver; import org.jetbrains.jet.lang.resolve.calls.CallResolver; -import org.jetbrains.jet.lang.resolve.calls.OverloadingConflictResolver; -import org.jetbrains.jet.lang.resolve.java.*; import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices; - +import org.jetbrains.jet.lang.resolve.TypeResolver; +import org.jetbrains.jet.lang.resolve.QualifiedExpressionResolver; +import org.jetbrains.jet.lang.resolve.calls.OverloadingConflictResolver; +import org.jetbrains.jet.lang.resolve.ImportsResolver; +import org.jetbrains.jet.lang.resolve.DelegationResolver; +import org.jetbrains.jet.lang.resolve.NamespaceFactoryImpl; +import org.jetbrains.jet.lang.resolve.OverloadResolver; +import org.jetbrains.jet.lang.resolve.OverrideResolver; +import org.jetbrains.jet.lang.resolve.TypeHierarchyResolver; +import org.jetbrains.jet.lang.resolve.java.JavaSemanticServices; +import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver; +import org.jetbrains.jet.lang.resolve.java.JavaTypeTransformer; +import com.intellij.openapi.project.Project; +import org.jetbrains.jet.lang.resolve.TopDownAnalysisParameters; +import org.jetbrains.jet.lang.resolve.ObservableBindingTrace; +import org.jetbrains.jet.lang.descriptors.ModuleDescriptor; +import org.jetbrains.jet.lang.resolve.java.CompilerDependencies; +import org.jetbrains.annotations.NotNull; import javax.annotation.PreDestroy; /* This file is generated by org.jetbrains.jet.di.AllInjectorsGenerator. DO NOT EDIT! */ @@ -42,7 +68,6 @@ public class InjectorForTopDownAnalyzerForJvm { private final TopDownAnalysisParameters topDownAnalysisParameters; private final ObservableBindingTrace observableBindingTrace; private final ModuleDescriptor moduleDescriptor; - private final JetControlFlowDataTraceFactory jetControlFlowDataTraceFactory; private final CompilerDependencies compilerDependencies; private CompilerSpecialMode compilerSpecialMode; private JavaBridgeConfiguration javaBridgeConfiguration; @@ -69,7 +94,6 @@ public class InjectorForTopDownAnalyzerForJvm { @NotNull TopDownAnalysisParameters topDownAnalysisParameters, @NotNull ObservableBindingTrace observableBindingTrace, @NotNull ModuleDescriptor moduleDescriptor, - JetControlFlowDataTraceFactory jetControlFlowDataTraceFactory, @NotNull CompilerDependencies compilerDependencies ) { this.topDownAnalyzer = new TopDownAnalyzer(); @@ -82,7 +106,6 @@ public class InjectorForTopDownAnalyzerForJvm { this.topDownAnalysisParameters = topDownAnalysisParameters; this.observableBindingTrace = observableBindingTrace; this.moduleDescriptor = moduleDescriptor; - this.jetControlFlowDataTraceFactory = jetControlFlowDataTraceFactory; this.compilerDependencies = compilerDependencies; this.compilerSpecialMode = compilerDependencies.getCompilerSpecialMode(); this.javaBridgeConfiguration = new JavaBridgeConfiguration(); @@ -126,7 +149,6 @@ public class InjectorForTopDownAnalyzerForJvm { this.bodyResolver.setTopDownAnalysisParameters(topDownAnalysisParameters); this.bodyResolver.setTrace(observableBindingTrace); - this.controlFlowAnalyzer.setFlowDataTraceFactory(jetControlFlowDataTraceFactory); this.controlFlowAnalyzer.setTopDownAnalysisParameters(topDownAnalysisParameters); this.controlFlowAnalyzer.setTrace(observableBindingTrace); diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AnalyzerFacadeForJVM.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AnalyzerFacadeForJVM.java index 75e2cf1db01..5b14ec0e973 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AnalyzerFacadeForJVM.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AnalyzerFacadeForJVM.java @@ -24,7 +24,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.analyzer.AnalyzeExhaust; import org.jetbrains.jet.analyzer.AnalyzerFacade; import org.jetbrains.jet.di.InjectorForTopDownAnalyzerForJvm; -import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; import org.jetbrains.jet.lang.descriptors.ModuleDescriptor; import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.resolve.*; @@ -50,9 +49,8 @@ public enum AnalyzerFacadeForJVM implements AnalyzerFacade { @NotNull public AnalyzeExhaust analyzeFiles(@NotNull Project project, @NotNull Collection files, - @NotNull Predicate filesToAnalyzeCompletely, - @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) { - return analyzeFilesWithJavaIntegration(project, files, filesToAnalyzeCompletely, flowDataTraceFactory, + @NotNull Predicate filesToAnalyzeCompletely) { + return analyzeFilesWithJavaIntegration(project, files, filesToAnalyzeCompletely, compilerDependenciesForProduction(CompilerSpecialMode.REGULAR), true); } @@ -60,22 +58,19 @@ public enum AnalyzerFacadeForJVM implements AnalyzerFacade { @Override public AnalyzeExhaust analyzeBodiesInFiles(@NotNull Project project, @NotNull Predicate filesForBodiesResolve, - @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory, @NotNull BindingTrace headersTraceContext, @NotNull BodiesResolveContext bodiesResolveContext ) { return analyzeBodiesInFilesWithJavaIntegration( - project, filesForBodiesResolve, flowDataTraceFactory, - compilerDependenciesForProduction(CompilerSpecialMode.REGULAR), + project, filesForBodiesResolve, compilerDependenciesForProduction(CompilerSpecialMode.REGULAR), headersTraceContext, bodiesResolveContext); } public static AnalyzeExhaust analyzeOneFileWithJavaIntegrationAndCheckForErrors( - JetFile file, JetControlFlowDataTraceFactory flowDataTraceFactory, - @NotNull CompilerDependencies compilerDependencies) { + JetFile file, @NotNull CompilerDependencies compilerDependencies) { AnalyzingUtils.checkForSyntacticErrors(file); - AnalyzeExhaust analyzeExhaust = analyzeOneFileWithJavaIntegration(file, flowDataTraceFactory, compilerDependencies); + AnalyzeExhaust analyzeExhaust = analyzeOneFileWithJavaIntegration(file, compilerDependencies); AnalyzingUtils.throwExceptionOnErrors(analyzeExhaust.getBindingContext()); @@ -83,24 +78,20 @@ public enum AnalyzerFacadeForJVM implements AnalyzerFacade { } public static AnalyzeExhaust analyzeOneFileWithJavaIntegration( - JetFile file, JetControlFlowDataTraceFactory flowDataTraceFactory, - @NotNull CompilerDependencies compilerDependencies) { + JetFile file, @NotNull CompilerDependencies compilerDependencies) { return analyzeFilesWithJavaIntegration(file.getProject(), Collections.singleton(file), - Predicates.alwaysTrue(), flowDataTraceFactory, compilerDependencies); + Predicates.alwaysTrue(), compilerDependencies); } public static AnalyzeExhaust analyzeFilesWithJavaIntegration( Project project, Collection files, Predicate filesToAnalyzeCompletely, - JetControlFlowDataTraceFactory flowDataTraceFactory, @NotNull CompilerDependencies compilerDependencies) { return analyzeFilesWithJavaIntegration( - project, files, filesToAnalyzeCompletely, - flowDataTraceFactory, compilerDependencies, false); + project, files, filesToAnalyzeCompletely, compilerDependencies, false); } public static AnalyzeExhaust analyzeFilesWithJavaIntegration( Project project, Collection files, Predicate filesToAnalyzeCompletely, - JetControlFlowDataTraceFactory flowDataTraceFactory, @NotNull CompilerDependencies compilerDependencies, boolean storeContextForBodiesResolve) { BindingTraceContext bindingTraceContext = new BindingTraceContext(); @@ -112,8 +103,7 @@ public enum AnalyzerFacadeForJVM implements AnalyzerFacade { InjectorForTopDownAnalyzerForJvm injector = new InjectorForTopDownAnalyzerForJvm( project, topDownAnalysisParameters, - new ObservableBindingTrace(bindingTraceContext), owner, flowDataTraceFactory, - compilerDependencies); + new ObservableBindingTrace(bindingTraceContext), owner, compilerDependencies); try { injector.getTopDownAnalyzer().analyzeFiles(files); BodiesResolveContext bodiesResolveContext = storeContextForBodiesResolve ? @@ -127,7 +117,6 @@ public enum AnalyzerFacadeForJVM implements AnalyzerFacade { public static AnalyzeExhaust analyzeBodiesInFilesWithJavaIntegration( Project project, Predicate filesToAnalyzeCompletely, - JetControlFlowDataTraceFactory flowDataTraceFactory, @NotNull CompilerDependencies compilerDependencies, @NotNull BindingTrace traceContext, @NotNull BodiesResolveContext bodiesResolveContext) { @@ -140,8 +129,7 @@ public enum AnalyzerFacadeForJVM implements AnalyzerFacade { InjectorForTopDownAnalyzerForJvm injector = new InjectorForTopDownAnalyzerForJvm( project, topDownAnalysisParameters, - new ObservableBindingTrace(traceContext), owner, flowDataTraceFactory, - compilerDependencies); + new ObservableBindingTrace(traceContext), owner, compilerDependencies); try { injector.getTopDownAnalyzer().doProcessForBodies(bodiesResolveContext); @@ -157,7 +145,6 @@ public enum AnalyzerFacadeForJVM implements AnalyzerFacade { Project project = files.iterator().next().getProject(); - return analyzeFilesWithJavaIntegration(project, files, Predicates.alwaysFalse(), - JetControlFlowDataTraceFactory.EMPTY, compilerDependencies); + return analyzeFilesWithJavaIntegration(project, files, Predicates.alwaysFalse(), compilerDependencies); } } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java index e69bf8ee9af..506ce076cac 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java @@ -49,7 +49,7 @@ import java.util.*; /** * @author abreslav */ -public class JavaDescriptorResolver { +public class JavaDescriptorResolver implements DependencyClassByQualifiedNameResolver { public static final Name JAVA_ROOT = Name.special(""); @@ -107,14 +107,14 @@ public class JavaDescriptorResolver { @NotNull private final TypeParameterDescriptorOrigin origin; @NotNull - final TypeParameterDescriptor descriptor; + final TypeParameterDescriptorImpl descriptor; final PsiTypeParameter psiTypeParameter; @Nullable private final List upperBoundsForKotlin; @Nullable private final List lowerBoundsForKotlin; - private TypeParameterDescriptorInitialization(@NotNull TypeParameterDescriptor descriptor, @NotNull PsiTypeParameter psiTypeParameter) { + private TypeParameterDescriptorInitialization(@NotNull TypeParameterDescriptorImpl descriptor, @NotNull PsiTypeParameter psiTypeParameter) { this.origin = TypeParameterDescriptorOrigin.JAVA; this.descriptor = descriptor; this.psiTypeParameter = psiTypeParameter; @@ -122,7 +122,7 @@ public class JavaDescriptorResolver { this.lowerBoundsForKotlin = null; } - private TypeParameterDescriptorInitialization(@NotNull TypeParameterDescriptor descriptor, @NotNull PsiTypeParameter psiTypeParameter, + private TypeParameterDescriptorInitialization(@NotNull TypeParameterDescriptorImpl descriptor, @NotNull PsiTypeParameter psiTypeParameter, List upperBoundsForKotlin, List lowerBoundsForKotlin) { this.origin = TypeParameterDescriptorOrigin.KOTLIN; this.descriptor = descriptor; @@ -307,6 +307,11 @@ public class JavaDescriptorResolver { return clazz; } + @Override + public ClassDescriptor resolveClass(@NotNull FqName qualifiedName) { + return resolveClass(qualifiedName, DescriptorSearchRule.ERROR_IF_FOUND_IN_KOTLIN); + } + private ClassDescriptor resolveClass(@NotNull FqName qualifiedName, @NotNull DescriptorSearchRule searchRule, @NotNull List tasks) { if (qualifiedName.getFqName().endsWith(JvmAbi.TRAIT_IMPL_SUFFIX)) { // TODO: only if -$$TImpl class is created by Kotlin @@ -603,10 +608,10 @@ public class JavaDescriptorResolver { @NotNull private final TypeVariableResolver typeVariableResolver; @NotNull - private final TypeParameterDescriptor typeParameterDescriptor; + private final TypeParameterDescriptorImpl typeParameterDescriptor; protected JetSignatureTypeParameterVisitor(PsiTypeParameterListOwner psiOwner, - String name, TypeVariableResolver typeVariableResolver, TypeParameterDescriptor typeParameterDescriptor) + String name, TypeVariableResolver typeVariableResolver, TypeParameterDescriptorImpl typeParameterDescriptor) { if (name.isEmpty()) { throw new IllegalStateException(); @@ -682,7 +687,7 @@ public class JavaDescriptorResolver { @Override public JetSignatureVisitor visitFormalTypeParameter(final String name, final TypeInfoVariance variance, boolean reified) { - TypeParameterDescriptor typeParameter = TypeParameterDescriptor.createForFurtherModification( + TypeParameterDescriptorImpl typeParameter = TypeParameterDescriptorImpl.createForFurtherModification( containingDeclaration, Collections.emptyList(), // TODO: wrong reified, @@ -757,7 +762,7 @@ public class JavaDescriptorResolver { @NotNull private TypeParameterDescriptorInitialization makeUninitializedTypeParameter(@NotNull DeclarationDescriptor containingDeclaration, @NotNull PsiTypeParameter psiTypeParameter) { - TypeParameterDescriptor typeParameterDescriptor = TypeParameterDescriptor.createForFurtherModification( + TypeParameterDescriptorImpl typeParameterDescriptor = TypeParameterDescriptorImpl.createForFurtherModification( containingDeclaration, Collections.emptyList(), // TODO false, @@ -769,7 +774,7 @@ public class JavaDescriptorResolver { } private void initializeTypeParameter(TypeParameterDescriptorInitialization typeParameter, TypeVariableResolver typeVariableByPsiResolver) { - TypeParameterDescriptor typeParameterDescriptor = typeParameter.descriptor; + TypeParameterDescriptorImpl typeParameterDescriptor = typeParameter.descriptor; if (typeParameter.origin == TypeParameterDescriptorOrigin.KOTLIN) { List upperBounds = typeParameter.upperBoundsForKotlin; if (upperBounds.size() == 0){ @@ -947,6 +952,11 @@ public class JavaDescriptorResolver { return scopeData.namespaceDescriptor; } + @Override + public NamespaceDescriptor resolveNamespace(@NotNull FqName qualifiedName) { + return resolveNamespace(qualifiedName, DescriptorSearchRule.ERROR_IF_FOUND_IN_KOTLIN); + } + private NamespaceDescriptorParent resolveParentNamespace(FqName fqName) { if (fqName.isRoot()) { return FAKE_ROOT_MODULE; diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/TypeVariableResolverFromTypeDescriptors.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/TypeVariableResolverFromTypeDescriptors.java index ed1f6235fff..aedd1e8bef1 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/TypeVariableResolverFromTypeDescriptors.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/TypeVariableResolverFromTypeDescriptors.java @@ -17,7 +17,6 @@ package org.jetbrains.jet.lang.resolve.java; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.ClassOrNamespaceDescriptor; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/TypeVariableResolvers.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/TypeVariableResolvers.java index 3a63089762c..858625e4c93 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/TypeVariableResolvers.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/TypeVariableResolvers.java @@ -17,12 +17,7 @@ package org.jetbrains.jet.lang.resolve.java; import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.descriptors.ClassDescriptor; -import org.jetbrains.jet.lang.descriptors.ClassOrNamespaceDescriptor; -import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; -import org.jetbrains.jet.lang.descriptors.ModuleDescriptor; -import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; -import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; +import org.jetbrains.jet.lang.descriptors.*; import java.util.ArrayList; import java.util.List; diff --git a/compiler/frontend/src/org/jetbrains/jet/analyzer/AnalyzerFacade.java b/compiler/frontend/src/org/jetbrains/jet/analyzer/AnalyzerFacade.java index a80a65f787f..b5fd8f9768a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/analyzer/AnalyzerFacade.java +++ b/compiler/frontend/src/org/jetbrains/jet/analyzer/AnalyzerFacade.java @@ -20,7 +20,6 @@ import com.google.common.base.Predicate; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiFile; import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.resolve.BindingTrace; import org.jetbrains.jet.lang.resolve.BodiesResolveContext; @@ -35,13 +34,11 @@ public interface AnalyzerFacade { @NotNull AnalyzeExhaust analyzeFiles(@NotNull Project project, @NotNull Collection files, - @NotNull Predicate filesToAnalyzeCompletely, - @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory); + @NotNull Predicate filesToAnalyzeCompletely); @NotNull AnalyzeExhaust analyzeBodiesInFiles(@NotNull Project project, @NotNull Predicate filesForBodiesResolve, - @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory, @NotNull BindingTrace traceContext, @NotNull BodiesResolveContext bodiesResolveContext); } diff --git a/compiler/frontend/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerBasic.java b/compiler/frontend/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerBasic.java index 843ec10293a..6dda0b5f2e6 100644 --- a/compiler/frontend/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerBasic.java +++ b/compiler/frontend/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerBasic.java @@ -17,16 +17,36 @@ package org.jetbrains.jet.di; +import org.jetbrains.jet.lang.resolve.TopDownAnalyzer; +import org.jetbrains.jet.lang.resolve.TopDownAnalysisContext; +import org.jetbrains.jet.lang.resolve.BodyResolver; +import org.jetbrains.jet.lang.resolve.ControlFlowAnalyzer; +import org.jetbrains.jet.lang.resolve.DeclarationsChecker; +import org.jetbrains.jet.lang.resolve.DescriptorResolver; import com.intellij.openapi.project.Project; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.ModuleConfiguration; -import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; +import org.jetbrains.jet.lang.resolve.TopDownAnalysisParameters; +import org.jetbrains.jet.lang.resolve.ObservableBindingTrace; import org.jetbrains.jet.lang.descriptors.ModuleDescriptor; -import org.jetbrains.jet.lang.resolve.*; +import org.jetbrains.jet.lang.ModuleConfiguration; +import org.jetbrains.jet.lang.resolve.DeclarationResolver; +import org.jetbrains.jet.lang.resolve.AnnotationResolver; import org.jetbrains.jet.lang.resolve.calls.CallResolver; -import org.jetbrains.jet.lang.resolve.calls.OverloadingConflictResolver; import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices; - +import org.jetbrains.jet.lang.resolve.TypeResolver; +import org.jetbrains.jet.lang.resolve.QualifiedExpressionResolver; +import org.jetbrains.jet.lang.resolve.calls.OverloadingConflictResolver; +import org.jetbrains.jet.lang.resolve.ImportsResolver; +import org.jetbrains.jet.lang.resolve.DelegationResolver; +import org.jetbrains.jet.lang.resolve.NamespaceFactoryImpl; +import org.jetbrains.jet.lang.resolve.OverloadResolver; +import org.jetbrains.jet.lang.resolve.OverrideResolver; +import org.jetbrains.jet.lang.resolve.TypeHierarchyResolver; +import com.intellij.openapi.project.Project; +import org.jetbrains.jet.lang.resolve.TopDownAnalysisParameters; +import org.jetbrains.jet.lang.resolve.ObservableBindingTrace; +import org.jetbrains.jet.lang.descriptors.ModuleDescriptor; +import org.jetbrains.jet.lang.ModuleConfiguration; +import org.jetbrains.annotations.NotNull; import javax.annotation.PreDestroy; /* This file is generated by org.jetbrains.jet.di.AllInjectorsGenerator. DO NOT EDIT! */ @@ -42,7 +62,6 @@ public class InjectorForTopDownAnalyzerBasic { private final TopDownAnalysisParameters topDownAnalysisParameters; private final ObservableBindingTrace observableBindingTrace; private final ModuleDescriptor moduleDescriptor; - private final JetControlFlowDataTraceFactory jetControlFlowDataTraceFactory; private final ModuleConfiguration moduleConfiguration; private DeclarationResolver declarationResolver; private AnnotationResolver annotationResolver; @@ -63,7 +82,6 @@ public class InjectorForTopDownAnalyzerBasic { @NotNull TopDownAnalysisParameters topDownAnalysisParameters, @NotNull ObservableBindingTrace observableBindingTrace, @NotNull ModuleDescriptor moduleDescriptor, - JetControlFlowDataTraceFactory jetControlFlowDataTraceFactory, @NotNull ModuleConfiguration moduleConfiguration ) { this.topDownAnalyzer = new TopDownAnalyzer(); @@ -76,7 +94,6 @@ public class InjectorForTopDownAnalyzerBasic { this.topDownAnalysisParameters = topDownAnalysisParameters; this.observableBindingTrace = observableBindingTrace; this.moduleDescriptor = moduleDescriptor; - this.jetControlFlowDataTraceFactory = jetControlFlowDataTraceFactory; this.moduleConfiguration = moduleConfiguration; this.declarationResolver = new DeclarationResolver(); this.annotationResolver = new AnnotationResolver(); @@ -114,7 +131,6 @@ public class InjectorForTopDownAnalyzerBasic { this.bodyResolver.setTopDownAnalysisParameters(topDownAnalysisParameters); this.bodyResolver.setTrace(observableBindingTrace); - this.controlFlowAnalyzer.setFlowDataTraceFactory(jetControlFlowDataTraceFactory); this.controlFlowAnalyzer.setTopDownAnalysisParameters(topDownAnalysisParameters); this.controlFlowAnalyzer.setTrace(observableBindingTrace); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java index 18d4ddfd1c1..b1822200b66 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java @@ -18,6 +18,7 @@ package org.jetbrains.jet.lang.cfg; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode; import org.jetbrains.jet.lang.psi.*; import java.util.List; @@ -64,7 +65,7 @@ public interface JetControlFlowBuilder { // Subroutines void enterSubroutine(@NotNull JetDeclaration subroutine); - void exitSubroutine(@NotNull JetDeclaration subroutine); + Pseudocode exitSubroutine(@NotNull JetDeclaration subroutine); @NotNull JetElement getCurrentSubroutine(); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilderAdapter.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilderAdapter.java index e3f6d4df970..cb3d67b2b64 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilderAdapter.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilderAdapter.java @@ -18,6 +18,7 @@ package org.jetbrains.jet.lang.cfg; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode; import org.jetbrains.jet.lang.psi.*; import java.util.List; @@ -157,9 +158,9 @@ public class JetControlFlowBuilderAdapter implements JetControlFlowBuilder { } @Override - public void exitSubroutine(@NotNull JetDeclaration subroutine) { + public Pseudocode exitSubroutine(@NotNull JetDeclaration subroutine) { assert builder != null; - builder.exitSubroutine(subroutine); + return builder.exitSubroutine(subroutine); } @NotNull diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowGraphTraverser.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowGraphTraverser.java deleted file mode 100644 index bf42c3ec570..00000000000 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowGraphTraverser.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright 2010-2012 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.lang.cfg; - -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import com.intellij.openapi.util.Pair; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.cfg.pseudocode.*; - -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -/** - * @author svtk - */ -public class JetControlFlowGraphTraverser { - private final Pseudocode pseudocode; - private final boolean lookInside; - private final boolean straightDirection; - private final Map> dataMap = Maps.newLinkedHashMap(); - - public static JetControlFlowGraphTraverser create(@NotNull Pseudocode pseudocode, boolean lookInside, boolean straightDirection) { - return new JetControlFlowGraphTraverser(pseudocode, lookInside, straightDirection); - } - - private JetControlFlowGraphTraverser(@NotNull Pseudocode pseudocode, boolean lookInside, boolean straightDirection) { - this.pseudocode = pseudocode; - this.lookInside = lookInside; - this.straightDirection = straightDirection; - } - - @NotNull - private Instruction getStartInstruction(@NotNull Pseudocode pseudocode) { - return straightDirection ? pseudocode.getEnterInstruction() : pseudocode.getSinkInstruction(); - } - - public void collectInformationFromInstructionGraph( - @NotNull D initialDataValue, - @NotNull D initialDataValueForEnterInstruction, - @NotNull InstructionDataMergeStrategy instructionDataMergeStrategy) { - initializeDataMap(pseudocode, initialDataValue); - dataMap.put(getStartInstruction(pseudocode), - Pair.create(initialDataValueForEnterInstruction, initialDataValueForEnterInstruction)); - - boolean[] changed = new boolean[1]; - changed[0] = true; - while (changed[0]) { - changed[0] = false; - traverseSubGraph(pseudocode, instructionDataMergeStrategy, Collections.emptyList(), changed, false); - } - } - - private void initializeDataMap( - @NotNull Pseudocode pseudocode, - @NotNull D initialDataValue) { - List instructions = pseudocode.getInstructions(); - Pair initialPair = Pair.create(initialDataValue, initialDataValue); - for (Instruction instruction : instructions) { - dataMap.put(instruction, initialPair); - if (lookInside && instruction instanceof LocalDeclarationInstruction) { - initializeDataMap(((LocalDeclarationInstruction) instruction).getBody(), initialDataValue); - } - } - } - - private void traverseSubGraph( - @NotNull Pseudocode pseudocode, - @NotNull InstructionDataMergeStrategy instructionDataMergeStrategy, - @NotNull Collection previousSubGraphInstructions, - boolean[] changed, - boolean isLocal) { - List instructions = pseudocode.getInstructions(); - Instruction startInstruction = getStartInstruction(pseudocode); - - if (!straightDirection) { - instructions = Lists.newArrayList(instructions); - Collections.reverse(instructions); - } - for (Instruction instruction : instructions) { - boolean isStart = straightDirection ? instruction instanceof SubroutineEnterInstruction : instruction instanceof SubroutineSinkInstruction; - if (!isLocal && isStart) continue; - - Collection allPreviousInstructions; - Collection previousInstructions = straightDirection - ? instruction.getPreviousInstructions() - : instruction.getNextInstructions(); - - if (instruction == startInstruction && !previousSubGraphInstructions.isEmpty()) { - allPreviousInstructions = Lists.newArrayList(previousInstructions); - allPreviousInstructions.addAll(previousSubGraphInstructions); - } - else { - allPreviousInstructions = previousInstructions; - } - - if (lookInside && instruction instanceof LocalDeclarationInstruction) { - Pseudocode subroutinePseudocode = ((LocalDeclarationInstruction) instruction).getBody(); - traverseSubGraph(subroutinePseudocode, instructionDataMergeStrategy, previousInstructions, changed, true); - Instruction lastInstruction = straightDirection ? subroutinePseudocode.getSinkInstruction() : subroutinePseudocode.getEnterInstruction(); - Pair previousValue = dataMap.get(instruction); - Pair newValue = dataMap.get(lastInstruction); - if (!previousValue.equals(newValue)) { - changed[0] = true; - dataMap.put(instruction, newValue); - } - continue; - } - Pair previousDataValue = dataMap.get(instruction); - - Collection incomingEdgesData = Sets.newHashSet(); - - for (Instruction previousInstruction : allPreviousInstructions) { - Pair previousData = dataMap.get(previousInstruction); - if (previousData != null) { - incomingEdgesData.add(previousData.getSecond()); - } - } - Pair mergedData = instructionDataMergeStrategy.execute(instruction, incomingEdgesData); - if (!mergedData.equals(previousDataValue)) { - changed[0] = true; - dataMap.put(instruction, mergedData); - } - } - } - - public void traverseAndAnalyzeInstructionGraph( - @NotNull InstructionDataAnalyzeStrategy instructionDataAnalyzeStrategy) { - traverseAndAnalyzeInstructionGraph(pseudocode, instructionDataAnalyzeStrategy); - } - - private void traverseAndAnalyzeInstructionGraph( - @NotNull Pseudocode pseudocode, - @NotNull InstructionDataAnalyzeStrategy instructionDataAnalyzeStrategy) { - List instructions = pseudocode.getInstructions(); - if (!straightDirection) { - instructions = Lists.newArrayList(instructions); - Collections.reverse(instructions); - } - for (Instruction instruction : instructions) { - if (lookInside && instruction instanceof LocalDeclarationInstruction) { - traverseAndAnalyzeInstructionGraph(((LocalDeclarationInstruction) instruction).getBody(), instructionDataAnalyzeStrategy); - } - Pair pair = dataMap.get(instruction); - instructionDataAnalyzeStrategy.execute(instruction, - pair != null ? pair.getFirst() : null, - pair != null ? pair.getSecond() : null); - } - } - - public D getResultInfo() { - return dataMap.get(pseudocode.getExitInstruction()).getFirst(); - } - - interface InstructionDataMergeStrategy { - Pair execute(@NotNull Instruction instruction, @NotNull Collection incomingEdgesData); - } - - interface InstructionDataAnalyzeStrategy { - void execute(@NotNull Instruction instruction, @Nullable D enterData, @Nullable D exitData); - } -} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java index 004e2cc739a..4a2fd8bb33a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java @@ -21,6 +21,10 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.tree.IElementType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.cfg.pseudocode.LocalDeclarationInstruction; +import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode; +import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowInstructionsGenerator; +import org.jetbrains.jet.lang.cfg.pseudocode.PseudocodeImpl; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContextUtils; @@ -45,12 +49,21 @@ public class JetControlFlowProcessor { private final JetControlFlowBuilder builder; private final BindingTrace trace; - public JetControlFlowProcessor(BindingTrace trace, JetControlFlowBuilder builder) { - this.builder = builder; + public JetControlFlowProcessor(BindingTrace trace) { + this.builder = new JetControlFlowInstructionsGenerator(); this.trace = trace; } - public void generate(@NotNull JetDeclaration subroutine) { + public Pseudocode generatePseudocode(@NotNull JetDeclaration subroutine) { + Pseudocode pseudocode = generate(subroutine); + ((PseudocodeImpl)pseudocode).postProcess(); + for (LocalDeclarationInstruction localDeclarationInstruction : pseudocode.getLocalDeclarations()) { + ((PseudocodeImpl)localDeclarationInstruction.getBody()).postProcess(); + } + return pseudocode; + } + + private Pseudocode generate(@NotNull JetDeclaration subroutine) { builder.enterSubroutine(subroutine); if (subroutine instanceof JetDeclarationWithBody) { JetDeclarationWithBody declarationWithBody = (JetDeclarationWithBody) subroutine; @@ -67,7 +80,7 @@ public class JetControlFlowProcessor { else { subroutine.accept(new CFPVisitor(false)); } - builder.exitSubroutine(subroutine); + return builder.exitSubroutine(subroutine); } private void processLocalDeclaration(@NotNull JetDeclaration subroutine) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java index a30b1de310f..be6a8f0028b 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java @@ -17,15 +17,16 @@ package org.jetbrains.jet.lang.cfg; import com.google.common.collect.Lists; -import com.google.common.collect.Maps; import com.google.common.collect.Sets; -import com.intellij.openapi.util.Pair; import com.intellij.psi.PsiElement; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.cfg.pseudocode.*; +import org.jetbrains.jet.lang.cfg.PseudocodeTraverser.*; +import org.jetbrains.jet.lang.cfg.PseudocodeVariablesData.VariableInitState; +import org.jetbrains.jet.lang.cfg.PseudocodeVariablesData.VariableUseState; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.diagnostics.Errors; import org.jetbrains.jet.lang.psi.*; @@ -33,13 +34,14 @@ import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContextUtils; import org.jetbrains.jet.lang.resolve.BindingTrace; import org.jetbrains.jet.lang.resolve.DescriptorUtils; -import org.jetbrains.jet.lang.types.lang.JetStandardClasses; import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.lang.JetStandardClasses; import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.plugin.JetMainDetector; import java.util.*; +import static org.jetbrains.jet.lang.cfg.PseudocodeVariablesData.VariableUseState.*; import static org.jetbrains.jet.lang.diagnostics.Errors.*; import static org.jetbrains.jet.lang.resolve.BindingContext.CAPTURED_IN_CLOSURE; import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE; @@ -49,52 +51,22 @@ import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE; */ public class JetFlowInformationProvider { - private final Map pseudocodeMap; + private final JetDeclaration subroutine; + private final Pseudocode pseudocode; + private final PseudocodeVariablesData pseudocodeVariablesData; private BindingTrace trace; - public JetFlowInformationProvider(@NotNull JetDeclaration declaration, @NotNull final JetExpression bodyExpression, @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory, @NotNull BindingTrace trace) { + public JetFlowInformationProvider( + @NotNull JetDeclaration declaration, + @NotNull BindingTrace trace) { + + subroutine = declaration; this.trace = trace; - final JetPseudocodeTrace pseudocodeTrace = flowDataTraceFactory.createTrace(declaration); - pseudocodeMap = new HashMap(); - final Map representativeInstructions = new HashMap(); - final Map loopInfo = Maps.newHashMap(); - JetPseudocodeTrace wrappedTrace = new JetPseudocodeTrace() { - @Override - public void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode) { - pseudocodeTrace.recordControlFlowData(element, pseudocode); - pseudocodeMap.put(element, pseudocode); - } - - @Override - public void recordRepresentativeInstruction(@NotNull JetElement element, @NotNull Instruction instruction) { - Instruction oldValue = representativeInstructions.put(element, instruction); -// assert oldValue == null : element.getText(); - pseudocodeTrace.recordRepresentativeInstruction(element, instruction); - } - - @Override - public void recordLoopInfo(JetExpression expression, LoopInfo blockInfo) { - loopInfo.put(expression, blockInfo); - pseudocodeTrace.recordLoopInfo(expression, blockInfo); - } - - @Override - public void close() { - pseudocodeTrace.close(); - for (Pseudocode pseudocode : pseudocodeMap.values()) { - pseudocode.postProcess(); - } - } - }; - JetControlFlowInstructionsGenerator instructionsGenerator = new JetControlFlowInstructionsGenerator(wrappedTrace); - new JetControlFlowProcessor(trace, instructionsGenerator).generate(declaration); - wrappedTrace.close(); + pseudocode = new JetControlFlowProcessor(trace).generatePseudocode(declaration); + pseudocodeVariablesData = new PseudocodeVariablesData(pseudocode, trace.getBindingContext()); } - private void collectReturnExpressions(@NotNull JetElement subroutine, @NotNull final Collection returnedExpressions) { - Pseudocode pseudocode = pseudocodeMap.get(subroutine); - assert pseudocode != null; - + private void collectReturnExpressions(@NotNull final Collection returnedExpressions) { final Set instructions = Sets.newHashSet(pseudocode.getInstructions()); SubroutineExitInstruction exitInstruction = pseudocode.getExitInstruction(); for (Instruction previousInstruction : exitInstruction.getPreviousInstructions()) { @@ -148,15 +120,16 @@ public class JetFlowInformationProvider { }); } } - - public void checkDefiniteReturn(@NotNull final JetDeclarationWithBody function, final @NotNull JetType expectedReturnType) { - assert function instanceof JetDeclaration; + + public void checkDefiniteReturn(final @NotNull JetType expectedReturnType) { + assert subroutine instanceof JetDeclarationWithBody; + JetDeclarationWithBody function = (JetDeclarationWithBody) subroutine; JetExpression bodyExpression = function.getBodyExpression(); if (bodyExpression == null) return; - + List returnedExpressions = Lists.newArrayList(); - collectReturnExpressions(function.asElement(), returnedExpressions); + collectReturnExpressions(returnedExpressions); boolean nothingReturned = returnedExpressions.isEmpty(); @@ -166,8 +139,8 @@ public class JetFlowInformationProvider { trace.report(RETURN_TYPE_MISMATCH.on(bodyExpression, expectedReturnType)); } final boolean blockBody = function.hasBlockBody(); - - final Set rootUnreachableElements = collectUnreachableCode(function.asElement()); + + final Set rootUnreachableElements = collectUnreachableCode(); for (JetElement element : rootUnreachableElements) { trace.report(UNREACHABLE_CODE.on(element)); } @@ -195,10 +168,7 @@ public class JetFlowInformationProvider { } } - private Set collectUnreachableCode(@NotNull JetElement subroutine) { - Pseudocode pseudocode = pseudocodeMap.get(subroutine); - assert pseudocode != null; - + private Set collectUnreachableCode() { Collection unreachableElements = Lists.newArrayList(); for (Instruction deadInstruction : pseudocode.getDeadInstructions()) { if (deadInstruction instanceof JetElementInstruction && @@ -213,73 +183,61 @@ public class JetFlowInformationProvider { //////////////////////////////////////////////////////////////////////////////// // Uninitialized variables analysis - public void markUninitializedVariables(@NotNull JetElement subroutine, final boolean processLocalDeclaration) { - final Pseudocode pseudocode = pseudocodeMap.get(subroutine); - assert pseudocode != null; - - JetControlFlowGraphTraverser> traverser = JetControlFlowGraphTraverser.create(pseudocode, false, true); - - Collection usedVariables = collectUsedVariables(pseudocode); - final Collection declaredVariables = collectDeclaredVariables(subroutine); - Map initialMapForStartInstruction = prepareInitialMapForStartInstruction(usedVariables, declaredVariables); - - traverser.collectInformationFromInstructionGraph(Collections.emptyMap(), initialMapForStartInstruction, - new JetControlFlowGraphTraverser.InstructionDataMergeStrategy>() { - @Override - public Pair, Map> execute( - @NotNull Instruction instruction, - @NotNull Collection> incomingEdgesData) { - - Map enterInstructionData = mergeIncomingEdgesData(incomingEdgesData); - Map exitInstructionData = addVariableInitializerFromCurrentInstructionIfAny(instruction, enterInstructionData); - return Pair.create(enterInstructionData, exitInstructionData); - } - }); - + public void markUninitializedVariables(final boolean processLocalDeclaration) { final Collection varWithUninitializedErrorGenerated = Sets.newHashSet(); final Collection varWithValReassignErrorGenerated = Sets.newHashSet(); final boolean processClassOrObject = subroutine instanceof JetClassOrObject; - traverser.traverseAndAnalyzeInstructionGraph(new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy>() { + + Map>> initializers = pseudocodeVariablesData.getVariableInitializers(); + final Set declaredVariables = pseudocodeVariablesData.getDeclaredVariables(pseudocode); + PseudocodeTraverser.traverse(pseudocode, true, true, initializers, new InstructionDataAnalyzeStrategy>() { @Override - public void execute(@NotNull Instruction instruction, @Nullable Map enterData, @Nullable Map exitData) { - assert enterData != null && exitData != null; - VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction, true); + public void execute(@NotNull Instruction instruction, + @Nullable Map in, + @Nullable Map out) { + assert in != null && out != null; + VariableDescriptor variableDescriptor = PseudocodeUtil.extractVariableDescriptorIfAny(instruction, true, trace.getBindingContext()); if (variableDescriptor == null) return; + if (!(instruction instanceof ReadValueInstruction) && !(instruction instanceof WriteValueInstruction)) return; + VariableInitState outInitState = out.get(variableDescriptor); if (instruction instanceof ReadValueInstruction) { JetElement element = ((ReadValueInstruction) instruction).getElement(); boolean error = checkBackingField(variableDescriptor, element); if (!error && declaredVariables.contains(variableDescriptor)) { - checkIsInitialized(variableDescriptor, element, exitData.get(variableDescriptor), varWithUninitializedErrorGenerated); + checkIsInitialized(variableDescriptor, element, outInitState, varWithUninitializedErrorGenerated); } + return; } - else if (instruction instanceof WriteValueInstruction) { - JetElement element = ((WriteValueInstruction) instruction).getlValue(); - boolean error = checkBackingField(variableDescriptor, element); - if (!(element instanceof JetExpression)) return; - if (!error && !processLocalDeclaration) { // error has been generated before, while processing outer function of this local declaration - error = checkValReassignment(variableDescriptor, (JetExpression) element, enterData.get(variableDescriptor), varWithValReassignErrorGenerated); - } - if (!error && processClassOrObject) { - error = checkAssignmentBeforeDeclaration(variableDescriptor, (JetExpression) element, enterData.get(variableDescriptor), exitData.get(variableDescriptor)); - } - if (!error && processClassOrObject) { - checkInitializationUsingBackingField(variableDescriptor, (JetExpression) element, enterData.get(variableDescriptor), exitData.get(variableDescriptor)); - } + JetElement element = ((WriteValueInstruction) instruction).getlValue(); + boolean error = checkBackingField(variableDescriptor, element); + if (!(element instanceof JetExpression)) return; + PseudocodeVariablesData.VariableInitState inInitState = in.get(variableDescriptor); + if (!error && !processLocalDeclaration) { // error has been generated before, while processing outer function of this local declaration + error = checkValReassignment(variableDescriptor, (JetExpression) element, inInitState, varWithValReassignErrorGenerated); + } + if (!error && processClassOrObject) { + error = checkAssignmentBeforeDeclaration(variableDescriptor, (JetExpression) element, inInitState, outInitState); + } + if (!error && processClassOrObject) { + checkInitializationUsingBackingField(variableDescriptor, (JetExpression) element, inInitState, outInitState); } } }); - recordInitializedVariables(declaredVariables, traverser.getResultInfo()); - analyzeLocalDeclarations(pseudocode, processLocalDeclaration); + Pseudocode pseudocode = pseudocodeVariablesData.getPseudocode(); + recordInitializedVariables(pseudocode, initializers); + for (LocalDeclarationInstruction instruction : pseudocode.getLocalDeclarations()) { + recordInitializedVariables(instruction.getBody(), initializers); + } } - private void checkIsInitialized(@NotNull VariableDescriptor variableDescriptor, - @NotNull JetElement element, - @NotNull VariableInitializers variableInitializers, + private void checkIsInitialized(@NotNull VariableDescriptor variableDescriptor, + @NotNull JetElement element, + @NotNull PseudocodeVariablesData.VariableInitState variableInitState, @NotNull Collection varWithUninitializedErrorGenerated) { if (!(element instanceof JetSimpleNameExpression)) return; - boolean isInitialized = variableInitializers.isInitialized(); + boolean isInitialized = variableInitState.isInitialized; if (variableDescriptor instanceof PropertyDescriptor) { if (!trace.get(BindingContext.BACKING_FIELD_REQUIRED, (PropertyDescriptor) variableDescriptor)) { isInitialized = true; @@ -288,7 +246,8 @@ public class JetFlowInformationProvider { if (!isInitialized && !varWithUninitializedErrorGenerated.contains(variableDescriptor)) { varWithUninitializedErrorGenerated.add(variableDescriptor); if (variableDescriptor instanceof ValueParameterDescriptor) { - trace.report(Errors.UNINITIALIZED_PARAMETER.on((JetSimpleNameExpression) element, (ValueParameterDescriptor) variableDescriptor)); + trace.report(Errors.UNINITIALIZED_PARAMETER.on((JetSimpleNameExpression) element, + (ValueParameterDescriptor) variableDescriptor)); } else { trace.report(Errors.UNINITIALIZED_VARIABLE.on((JetSimpleNameExpression) element, variableDescriptor)); @@ -296,17 +255,13 @@ public class JetFlowInformationProvider { } } - private boolean checkValReassignment(@NotNull VariableDescriptor variableDescriptor, - @NotNull JetExpression expression, - @NotNull VariableInitializers enterInitializers, + private boolean checkValReassignment(@NotNull VariableDescriptor variableDescriptor, + @NotNull JetExpression expression, + @NotNull VariableInitState enterInitState, @NotNull Collection varWithValReassignErrorGenerated) { - boolean isInitializedNotHere = enterInitializers.isInitialized(); - Set possibleLocalInitializers = enterInitializers.getPossibleLocalInitializers(); - if (possibleLocalInitializers.size() == 1) { - JetElement initializer = possibleLocalInitializers.iterator().next(); - if (initializer instanceof JetProperty && initializer == expression.getParent()) { - isInitializedNotHere = false; - } + boolean isInitializedNotHere = enterInitState.isInitialized; + if (expression.getParent() instanceof JetProperty && ((JetProperty)expression).getInitializer() != null) { + isInitializedNotHere = false; } boolean hasBackingField = true; if (variableDescriptor instanceof PropertyDescriptor) { @@ -348,17 +303,17 @@ public class JetFlowInformationProvider { } return false; } - - private boolean checkAssignmentBeforeDeclaration(@NotNull VariableDescriptor variableDescriptor, @NotNull JetExpression expression, @NotNull VariableInitializers enterInitializers, @NotNull VariableInitializers exitInitializers) { - if (!enterInitializers.isDeclared() && !exitInitializers.isDeclared() && !enterInitializers.isInitialized() && exitInitializers.isInitialized()) { + + private boolean checkAssignmentBeforeDeclaration(@NotNull VariableDescriptor variableDescriptor, @NotNull JetExpression expression, @NotNull VariableInitState enterInitState, @NotNull VariableInitState exitInitState) { + if (!enterInitState.isDeclared && !exitInitState.isDeclared && !enterInitState.isInitialized && exitInitState.isInitialized) { trace.report(Errors.INITIALIZATION_BEFORE_DECLARATION.on(expression, variableDescriptor)); return true; } return false; } - - private boolean checkInitializationUsingBackingField(@NotNull VariableDescriptor variableDescriptor, @NotNull JetExpression expression, @NotNull VariableInitializers enterInitializers, @NotNull VariableInitializers exitInitializers) { - if (variableDescriptor instanceof PropertyDescriptor && !enterInitializers.isInitialized() && exitInitializers.isInitialized()) { + + private boolean checkInitializationUsingBackingField(@NotNull VariableDescriptor variableDescriptor, @NotNull JetExpression expression, @NotNull VariableInitState enterInitState, @NotNull VariableInitState exitInitState) { + if (variableDescriptor instanceof PropertyDescriptor && !enterInitState.isInitialized && exitInitState.isInitialized) { if (!variableDescriptor.isVar()) return false; if (!trace.get(BindingContext.BACKING_FIELD_REQUIRED, (PropertyDescriptor) variableDescriptor)) return false; PsiElement property = BindingContextUtils.descriptorToDeclaration(trace.getBindingContext(), variableDescriptor); @@ -397,7 +352,9 @@ public class JetFlowInformationProvider { } PsiElement property = BindingContextUtils.descriptorToDeclaration(trace.getBindingContext(), variableDescriptor); boolean insideSelfAccessors = PsiTreeUtil.isAncestor(property, element, false); - if (!trace.get(BindingContext.BACKING_FIELD_REQUIRED, (PropertyDescriptor) variableDescriptor) && !insideSelfAccessors) { // not to generate error in accessors of abstract properties, there is one: declared accessor of abstract property + if (!trace.get(BindingContext.BACKING_FIELD_REQUIRED, (PropertyDescriptor) variableDescriptor) && + !insideSelfAccessors) { // not to generate error in accessors of abstract properties, there is one: declared accessor of abstract property + if (((PropertyDescriptor) variableDescriptor).getModality() == Modality.ABSTRACT) { trace.report(NO_BACKING_FIELD_ABSTRACT_PROPERTY.on(element)); } @@ -436,173 +393,44 @@ public class JetFlowInformationProvider { return false; } - private void recordInitializedVariables(Collection declaredVariables, Map resultInfo) { - for (Map.Entry entry : resultInfo.entrySet()) { - VariableDescriptor variable = entry.getKey(); - if (variable instanceof PropertyDescriptor && declaredVariables.contains(variable)) { - VariableInitializers initializers = entry.getValue(); - trace.record(BindingContext.IS_INITIALIZED, (PropertyDescriptor) variable, initializers.isInitialized()); - } - } - } - - private void analyzeLocalDeclarations(Pseudocode pseudocode, boolean processLocalDeclaration) { - for (Instruction instruction : pseudocode.getInstructions()) { - if (instruction instanceof LocalDeclarationInstruction) { - JetElement element = ((LocalDeclarationInstruction) instruction).getElement(); - markUninitializedVariables(element, processLocalDeclaration); - } - } - } - - private Map addVariableInitializerFromCurrentInstructionIfAny(Instruction instruction, Map enterInstructionData) { - Map exitInstructionData = Maps.newHashMap(enterInstructionData); - if (instruction instanceof WriteValueInstruction) { - VariableDescriptor variable = extractVariableDescriptorIfAny(instruction, false); - VariableInitializers enterInitializers = enterInstructionData.get(variable); - VariableInitializers initializationAtThisElement = new VariableInitializers(((WriteValueInstruction) instruction).getElement(), enterInitializers); - exitInstructionData.put(variable, initializationAtThisElement); - } - else if (instruction instanceof VariableDeclarationInstruction) { - VariableDescriptor variable = extractVariableDescriptorIfAny(instruction, false); - VariableInitializers enterInitializers = enterInstructionData.get(variable); - if (enterInitializers == null || !enterInitializers.isInitialized() || !enterInitializers.isDeclared()) { - JetElement element = ((VariableDeclarationInstruction) instruction).getElement(); - if (element instanceof JetProperty) { - JetProperty property = (JetProperty) element; - if (property.getInitializer() == null) { - boolean isInitialized = enterInitializers != null && enterInitializers.isInitialized(); - VariableInitializers variableDeclarationInfo = new VariableInitializers(isInitialized, true); - exitInstructionData.put(variable, variableDeclarationInfo); - } - } - } - } - return exitInstructionData; - } - - private Map mergeIncomingEdgesData(Collection> incomingEdgesData) { - Set variablesInScope = Sets.newHashSet(); - for (Map edgeData : incomingEdgesData) { - variablesInScope.addAll(edgeData.keySet()); - } - - Map enterInstructionData = Maps.newHashMap(); - for (VariableDescriptor variable : variablesInScope) { - Set edgesDataForVariable = Sets.newHashSet(); - for (Map edgeData : incomingEdgesData) { - VariableInitializers initializers = edgeData.get(variable); - if (initializers != null) { - edgesDataForVariable.add(initializers); - } - } - enterInstructionData.put(variable, new VariableInitializers(edgesDataForVariable)); - } - return enterInstructionData; - } - - private Map prepareInitialMapForStartInstruction(Collection usedVariables, Collection declaredVariables) { - Map initialMapForStartInstruction = Maps.newHashMap(); - VariableInitializers isInitializedForExternalVariable = new VariableInitializers(true); - VariableInitializers isNotInitializedForDeclaredVariable = new VariableInitializers(false); - + private void recordInitializedVariables(@NotNull Pseudocode pseudocode, @NotNull Map>> initializersMap) { + Edges> initializers = initializersMap.get(pseudocode.getExitInstruction()); + Set usedVariables = pseudocodeVariablesData.getUsedVariables(pseudocode); + Set declaredVariables = pseudocodeVariablesData.getDeclaredVariables(pseudocode); for (VariableDescriptor variable : usedVariables) { - if (declaredVariables.contains(variable)) { - initialMapForStartInstruction.put(variable, isNotInitializedForDeclaredVariable); - } - else { - initialMapForStartInstruction.put(variable, isInitializedForExternalVariable); + if (variable instanceof PropertyDescriptor && declaredVariables.contains(variable)) { + PseudocodeVariablesData.VariableInitState variableInitState = initializers.in.get(variable); + if (variableInitState == null) return; + trace.record(BindingContext.IS_INITIALIZED, (PropertyDescriptor) variable, variableInitState.isInitialized); } } - return initialMapForStartInstruction; - } - -//////////////////////////////////////////////////////////////////////////////// - - public void markNotOnlyInvokedFunctionVariables(@NotNull JetElement subroutine, List variables) { - final List functionVariables = Lists.newArrayList(); - for (VariableDescriptor variable : variables) { - if (JetStandardClasses.isFunctionType(variable.getReturnType())) { - functionVariables.add(variable); - } - } - - Pseudocode pseudocode = pseudocodeMap.get(subroutine); - assert pseudocode != null; - - JetControlFlowGraphTraverser.create(pseudocode, true, true).traverseAndAnalyzeInstructionGraph(new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy() { - @Override - public void execute(@NotNull Instruction instruction, Void enterData, Void exitData) { - if (instruction instanceof ReadValueInstruction) { - VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction, false); - if (variableDescriptor != null && functionVariables.contains(variableDescriptor)) { - //check that we only invoke this variable - JetElement element = ((ReadValueInstruction) instruction).getElement(); - if (element instanceof JetSimpleNameExpression && !(element.getParent() instanceof JetCallExpression)) { - trace.report(Errors.FUNCTION_PARAMETERS_OF_INLINE_FUNCTION.on((JetSimpleNameExpression) element, variableDescriptor)); - } - } - } - } - }); } //////////////////////////////////////////////////////////////////////////////// // "Unused variable" & "unused value" analyses - public void markUnusedVariables(@NotNull JetElement subroutine) { - Pseudocode pseudocode = pseudocodeMap.get(subroutine); - assert pseudocode != null; - JetControlFlowGraphTraverser> traverser = JetControlFlowGraphTraverser.create(pseudocode, true, false); - final Collection declaredVariables = collectDeclaredVariables(subroutine); - Map sinkInstructionData = Maps.newHashMap(); - traverser.collectInformationFromInstructionGraph(Collections.emptyMap(), sinkInstructionData, new JetControlFlowGraphTraverser.InstructionDataMergeStrategy>() { + public void markUnusedVariables() { + Map>> variableStatusData = pseudocodeVariablesData.getVariableUseStatusData(); + InstructionDataAnalyzeStrategy> variableStatusAnalyzeStrategy = + new InstructionDataAnalyzeStrategy>() { @Override - public Pair, Map> execute(@NotNull Instruction instruction, @NotNull Collection> incomingEdgesData) { - Map enterResult = Maps.newHashMap(); - for (Map edgeData : incomingEdgesData) { - for (Map.Entry entry : edgeData.entrySet()) { - VariableDescriptor variableDescriptor = entry.getKey(); - VariableStatus variableStatus = entry.getValue(); - enterResult.put(variableDescriptor, variableStatus.merge(enterResult.get(variableDescriptor))); - } - } - Map exitResult = Maps.newHashMap(enterResult); - VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction, true); - if (variableDescriptor != null) { - if (instruction instanceof ReadValueInstruction) { - exitResult.put(variableDescriptor, VariableStatus.READ); - } - else if (instruction instanceof WriteValueInstruction) { - VariableStatus variableStatus = enterResult.get(variableDescriptor); - if (variableStatus == null) variableStatus = VariableStatus.UNUSED; - switch(variableStatus) { - case UNUSED: - case ONLY_WRITTEN: - exitResult.put(variableDescriptor, VariableStatus.ONLY_WRITTEN); - break; - case WRITTEN: - case READ: - exitResult.put(variableDescriptor, VariableStatus.WRITTEN); - } - } - } - return new Pair, Map>(enterResult, exitResult); - } - }); - traverser.traverseAndAnalyzeInstructionGraph(new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy>() { - @Override - public void execute(@NotNull Instruction instruction, @Nullable Map enterData, @Nullable Map exitData) { - assert enterData != null && exitData != null; - VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction, false); + public void execute(@NotNull Instruction instruction, + @Nullable Map in, + @Nullable Map out) { + + assert in != null && out != null; + Set declaredVariables = pseudocodeVariablesData.getDeclaredVariables(instruction.getOwner()); + VariableDescriptor variableDescriptor = PseudocodeUtil.extractVariableDescriptorIfAny(instruction, false, + trace.getBindingContext()); if (variableDescriptor == null || !declaredVariables.contains(variableDescriptor) || !DescriptorUtils.isLocal(variableDescriptor.getContainingDeclaration(), variableDescriptor)) return; - VariableStatus variableStatus = enterData.get(variableDescriptor); + PseudocodeVariablesData.VariableUseState variableUseState = in.get(variableDescriptor); if (instruction instanceof WriteValueInstruction) { if (trace.get(CAPTURED_IN_CLOSURE, variableDescriptor)) return; JetElement element = ((WriteValueInstruction) instruction).getElement(); - if (variableStatus != VariableStatus.READ) { - if (element instanceof JetBinaryExpression && ((JetBinaryExpression) element).getOperationToken() == JetTokens.EQ) { + if (variableUseState != LAST_READ) { + if (element instanceof JetBinaryExpression && + ((JetBinaryExpression) element).getOperationToken() == JetTokens.EQ) { JetExpression right = ((JetBinaryExpression) element).getRight(); if (right != null) { trace.report(Errors.UNUSED_VALUE.on(right, right, variableDescriptor)); @@ -621,7 +449,7 @@ public class JetFlowInformationProvider { if (element instanceof JetNamedDeclaration) { PsiElement nameIdentifier = ((JetNamedDeclaration) element).getNameIdentifier(); if (nameIdentifier == null) return; - if (variableStatus == null || variableStatus == VariableStatus.UNUSED) { + if (!VariableUseState.isUsed(variableUseState)) { if (element instanceof JetProperty) { trace.report(Errors.UNUSED_VARIABLE.on((JetProperty) element, variableDescriptor)); } @@ -629,8 +457,9 @@ public class JetFlowInformationProvider { PsiElement psiElement = element.getParent().getParent(); if (psiElement instanceof JetFunction) { boolean isMain = (psiElement instanceof JetNamedFunction) && JetMainDetector.isMain((JetNamedFunction) psiElement); + if (psiElement instanceof JetFunctionLiteral) return; DeclarationDescriptor descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, psiElement); - assert descriptor instanceof FunctionDescriptor; + assert descriptor instanceof FunctionDescriptor : psiElement.getText(); FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor; if (!isMain && !functionDescriptor.getModality().isOverridable() && functionDescriptor.getOverriddenDescriptors().isEmpty()) { trace.report(Errors.UNUSED_PARAMETER.on((JetParameter) element, variableDescriptor)); @@ -638,52 +467,34 @@ public class JetFlowInformationProvider { } } } - else if (variableStatus == VariableStatus.ONLY_WRITTEN && element instanceof JetProperty) { + else if (variableUseState == ONLY_WRITTEN_NEVER_READ && element instanceof JetProperty) { trace.report(Errors.ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE.on((JetNamedDeclaration) element, variableDescriptor)); } - else if (variableStatus == VariableStatus.WRITTEN && element instanceof JetProperty) { + else if (variableUseState == LAST_WRITTEN && element instanceof JetProperty) { JetExpression initializer = ((JetProperty) element).getInitializer(); if (initializer != null) { trace.report(Errors.VARIABLE_WITH_REDUNDANT_INITIALIZER.on(initializer, variableDescriptor)); } } } - } } - }); - } - - private static enum VariableStatus { - READ(3), - WRITTEN(2), - ONLY_WRITTEN(1), - UNUSED(0); - - private int importance; - - private VariableStatus(int importance) { - this.importance = importance; - } - - public VariableStatus merge(@Nullable VariableStatus variableStatus) { - if (variableStatus == null || importance > variableStatus.importance) return this; - return variableStatus; - } + }; + PseudocodeTraverser.traverse(pseudocode, false, true, variableStatusData, variableStatusAnalyzeStrategy); } //////////////////////////////////////////////////////////////////////////////// // "Unused literals" in block - - public void markUnusedLiteralsInBlock(@NotNull JetElement subroutine) { - Pseudocode pseudocode = pseudocodeMap.get(subroutine); + + public void markUnusedLiteralsInBlock() { assert pseudocode != null; - JetControlFlowGraphTraverser traverser = JetControlFlowGraphTraverser.create(pseudocode, true, true); - traverser.traverseAndAnalyzeInstructionGraph(new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy() { + PseudocodeTraverser.traverse( + pseudocode, true, new InstructionAnalyzeStrategy() { @Override - public void execute(@NotNull Instruction instruction, @Nullable Void enterData, @Nullable Void exitData) { + public void execute(@NotNull Instruction instruction) { if (!(instruction instanceof ReadValueInstruction)) return; - JetElement element = ((ReadValueInstruction) instruction).getElement(); + JetElement element = + ((ReadValueInstruction) instruction).getElement(); if (!(element instanceof JetFunctionLiteralExpression || element instanceof JetConstantExpression || element instanceof JetStringTemplateExpression @@ -694,7 +505,8 @@ public class JetFlowInformationProvider { if (parent instanceof JetBlockExpression) { if (!JetPsiUtil.isImplicitlyUsed(element)) { if (element instanceof JetFunctionLiteralExpression) { - trace.report(Errors.UNUSED_FUNCTION_LITERAL.on((JetFunctionLiteralExpression) element)); + trace.report(Errors.UNUSED_FUNCTION_LITERAL + .on((JetFunctionLiteralExpression) element)); } else { trace.report(Errors.UNUSED_EXPRESSION.on(element)); @@ -704,133 +516,4 @@ public class JetFlowInformationProvider { } }); } - -//////////////////////////////////////////////////////////////////////////////// -// Util methods 7 - - @Nullable - private VariableDescriptor extractVariableDescriptorIfAny(Instruction instruction, boolean onlyReference) { - JetElement element = null; - if (instruction instanceof ReadValueInstruction) { - element = ((ReadValueInstruction) instruction).getElement(); - } - else if (instruction instanceof WriteValueInstruction) { - element = ((WriteValueInstruction) instruction).getlValue(); - } - else if (instruction instanceof VariableDeclarationInstruction) { - element = ((VariableDeclarationInstruction) instruction).getVariableDeclarationElement(); - } - return BindingContextUtils.extractVariableDescriptorIfAny(trace.getBindingContext(), element, onlyReference); - } - - private Collection collectUsedVariables(Pseudocode pseudocode) { - final Set usedVariables = Sets.newHashSet(); - JetControlFlowGraphTraverser.create(pseudocode, true, true).traverseAndAnalyzeInstructionGraph(new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy() { - @Override - public void execute(@NotNull Instruction instruction, Void enterData, Void exitData) { - VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction, false); - if (variableDescriptor != null) { - usedVariables.add(variableDescriptor); - } - } - }); - return usedVariables; - } - - private Collection collectDeclaredVariables(JetElement element) { - final Pseudocode pseudocode = pseudocodeMap.get(element); - assert pseudocode != null; - - final Set declaredVariables = Sets.newHashSet(); - JetControlFlowGraphTraverser.create(pseudocode, false, true).traverseAndAnalyzeInstructionGraph(new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy() { - @Override - public void execute(@NotNull Instruction instruction, @Nullable Void enterData, @Nullable Void exitData) { - if (instruction instanceof VariableDeclarationInstruction) { - JetDeclaration variableDeclarationElement = ((VariableDeclarationInstruction) instruction).getVariableDeclarationElement(); - DeclarationDescriptor descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, variableDeclarationElement); - if (descriptor != null) { - assert descriptor instanceof VariableDescriptor; - declaredVariables.add((VariableDescriptor) descriptor); - } - } - } - }); - return declaredVariables; - } - -//////////////////////////////////////////////////////////////////////////////// -// Local class for uninitialized variables analysis - - private static class VariableInitializers { - private Set possibleLocalInitializers = Sets.newHashSet(); - private boolean isInitialized; - private boolean isDeclared; - - public VariableInitializers(boolean isInitialized) { - this(isInitialized, false); - } - - public VariableInitializers(boolean isInitialized, boolean isDeclared) { - this.isInitialized = isInitialized; - this.isDeclared = isDeclared; - } - - public VariableInitializers(JetElement element, @Nullable VariableInitializers previous) { - isInitialized = true; - isDeclared = element instanceof JetProperty || (previous != null && previous.isDeclared()); - possibleLocalInitializers.add(element); - } - - public VariableInitializers(Set edgesData) { - isInitialized = true; - isDeclared = true; - for (VariableInitializers edgeData : edgesData) { - if (!edgeData.isInitialized) { - isInitialized = false; - } - if (!edgeData.isDeclared) { - isDeclared = false; - } - possibleLocalInitializers.addAll(edgeData.possibleLocalInitializers); - } - } - - public Set getPossibleLocalInitializers() { - return possibleLocalInitializers; - } - - public boolean isInitialized() { - return isInitialized; - } - - public boolean isDeclared() { - return isDeclared; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof VariableInitializers)) return false; - - VariableInitializers that = (VariableInitializers) o; - - if (isDeclared != that.isDeclared) return false; - if (isInitialized != that.isInitialized) return false; - if (possibleLocalInitializers != null - ? !possibleLocalInitializers.equals(that.possibleLocalInitializers) - : that.possibleLocalInitializers != null) { - return false; - } - - return true; - } - - @Override - public int hashCode() { - int result = possibleLocalInitializers != null ? possibleLocalInitializers.hashCode() : 0; - result = 31 * result + (isInitialized ? 1 : 0); - result = 31 * result + (isDeclared ? 1 : 0); - return result; - } - } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/PseudocodeTraverser.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/PseudocodeTraverser.java new file mode 100644 index 00000000000..2c31612629b --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/PseudocodeTraverser.java @@ -0,0 +1,204 @@ +/* + * Copyright 2010-2012 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.lang.cfg; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.cfg.pseudocode.*; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * @author svtk + */ +public class PseudocodeTraverser { + @NotNull + private static Instruction getStartInstruction(@NotNull Pseudocode pseudocode, boolean directOrder) { + return directOrder ? pseudocode.getEnterInstruction() : pseudocode.getSinkInstruction(); + } + + public static Map> collectData( + @NotNull Pseudocode pseudocode, boolean directOrder, boolean lookInside, + @NotNull D initialDataValue, @NotNull D initialDataValueForEnterInstruction, + @NotNull InstructionDataMergeStrategy instructionDataMergeStrategy) { + + Map> edgesMap = Maps.newLinkedHashMap(); + initializeEdgesMap(pseudocode, lookInside, edgesMap, initialDataValue); + edgesMap.put(getStartInstruction(pseudocode, directOrder), Edges.create(initialDataValueForEnterInstruction, initialDataValueForEnterInstruction)); + + boolean[] changed = new boolean[1]; + changed[0] = true; + while (changed[0]) { + changed[0] = false; + collectDataFromSubgraph(pseudocode, directOrder, lookInside, edgesMap, instructionDataMergeStrategy, + Collections.emptyList(), changed, false); + } + return edgesMap; + } + + private static void initializeEdgesMap( + @NotNull Pseudocode pseudocode, boolean lookInside, + @NotNull Map> edgesMap, + @NotNull D initialDataValue) { + List instructions = pseudocode.getInstructions(); + Edges initialEdge = Edges.create(initialDataValue, initialDataValue); + for (Instruction instruction : instructions) { + edgesMap.put(instruction, initialEdge); + if (lookInside && instruction instanceof LocalDeclarationInstruction) { + initializeEdgesMap(((LocalDeclarationInstruction) instruction).getBody(), lookInside, edgesMap, initialDataValue); + } + } + } + + private static void collectDataFromSubgraph( + @NotNull Pseudocode pseudocode, boolean directOrder, boolean lookInside, + @NotNull Map> edgesMap, + @NotNull InstructionDataMergeStrategy instructionDataMergeStrategy, + @NotNull Collection previousSubGraphInstructions, + boolean[] changed, boolean isLocal) { + + List instructions = directOrder ? pseudocode.getInstructions() : pseudocode.getReversedInstructions(); + Instruction startInstruction = getStartInstruction(pseudocode, directOrder); + + for (Instruction instruction : instructions) { + boolean isStart = directOrder ? instruction instanceof SubroutineEnterInstruction : instruction instanceof SubroutineSinkInstruction; + if (!isLocal && isStart) continue; + + Collection allPreviousInstructions; + Collection previousInstructions = directOrder ? instruction.getPreviousInstructions() : instruction.getNextInstructions(); + + if (instruction == startInstruction && !previousSubGraphInstructions.isEmpty()) { + allPreviousInstructions = Lists.newArrayList(previousInstructions); + allPreviousInstructions.addAll(previousSubGraphInstructions); + } + else { + allPreviousInstructions = previousInstructions; + } + + if (lookInside && instruction instanceof LocalDeclarationInstruction) { + Pseudocode subroutinePseudocode = ((LocalDeclarationInstruction) instruction).getBody(); + collectDataFromSubgraph(subroutinePseudocode, directOrder, lookInside, edgesMap, instructionDataMergeStrategy, + previousInstructions, + changed, true); + Instruction lastInstruction = directOrder ? subroutinePseudocode.getSinkInstruction() : subroutinePseudocode.getEnterInstruction(); + Edges previousValue = edgesMap.get(instruction); + Edges newValue = edgesMap.get(lastInstruction); + if (!previousValue.equals(newValue)) { + changed[0] = true; + edgesMap.put(instruction, newValue); + } + continue; + } + Edges previousDataValue = edgesMap.get(instruction); + + Collection incomingEdgesData = Sets.newHashSet(); + + for (Instruction previousInstruction : allPreviousInstructions) { + Edges previousData = edgesMap.get(previousInstruction); + if (previousData != null) { + incomingEdgesData.add(previousData.out); + } + } + Edges mergedData = instructionDataMergeStrategy.execute(instruction, incomingEdgesData); + if (!mergedData.equals(previousDataValue)) { + changed[0] = true; + edgesMap.put(instruction, mergedData); + } + } + } + + public static void traverse( + @NotNull Pseudocode pseudocode, boolean directOrder, + InstructionAnalyzeStrategy instructionAnalyzeStrategy) { + + List instructions = directOrder ? pseudocode.getInstructions() : pseudocode.getReversedInstructions(); + for (Instruction instruction : instructions) { + if (instruction instanceof LocalDeclarationInstruction) { + traverse(((LocalDeclarationInstruction) instruction).getBody(), directOrder, instructionAnalyzeStrategy); + } + instructionAnalyzeStrategy.execute(instruction); + } + } + + public static void traverse( + @NotNull Pseudocode pseudocode, boolean directOrder, boolean lookInside, + @NotNull Map> edgesMap, + @NotNull InstructionDataAnalyzeStrategy instructionDataAnalyzeStrategy) { + + List instructions = directOrder ? pseudocode.getInstructions() : pseudocode.getReversedInstructions(); + for (Instruction instruction : instructions) { + if (lookInside && instruction instanceof LocalDeclarationInstruction) { + traverse(((LocalDeclarationInstruction) instruction).getBody(), directOrder, lookInside, edgesMap, + instructionDataAnalyzeStrategy); + } + Edges edges = edgesMap.get(instruction); + instructionDataAnalyzeStrategy.execute(instruction, edges != null ? edges.in : null, edges != null ? edges.out : null); + } + } + + public interface InstructionDataMergeStrategy { + Edges execute(@NotNull Instruction instruction, @NotNull Collection incomingEdgesData); + } + + public interface InstructionDataAnalyzeStrategy { + void execute(@NotNull Instruction instruction, @Nullable D enterData, @Nullable D exitData); + } + + public interface InstructionAnalyzeStrategy { + void execute(@NotNull Instruction instruction); + } + + public static class Edges { + public final T in; + public final T out; + + Edges(@NotNull T in, @NotNull T out) { + this.in = in; + this.out = out; + } + + public static Edges create(@NotNull T in, @NotNull T out) { + return new Edges(in, out); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Edges)) return false; + + Edges edges = (Edges) o; + + if (in != null ? !in.equals(edges.in) : edges.in != null) return false; + if (out != null ? !out.equals(edges.out) : edges.out != null) return false; + + return true; + } + + @Override + public int hashCode() { + int result = in != null ? in.hashCode() : 0; + result = 31 * result + (out != null ? out.hashCode() : 0); + return result; + } + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/PseudocodeVariablesData.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/PseudocodeVariablesData.java new file mode 100644 index 00000000000..92f84ca62cd --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/PseudocodeVariablesData.java @@ -0,0 +1,348 @@ +/* + * Copyright 2010-2012 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.lang.cfg; + +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.cfg.PseudocodeTraverser.*; +import org.jetbrains.jet.lang.cfg.pseudocode.*; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; +import org.jetbrains.jet.lang.descriptors.VariableDescriptor; +import org.jetbrains.jet.lang.psi.JetDeclaration; +import org.jetbrains.jet.lang.psi.JetElement; +import org.jetbrains.jet.lang.psi.JetProperty; +import org.jetbrains.jet.lang.resolve.BindingContext; + +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.Set; + +/** + * @author svtk + */ +public class PseudocodeVariablesData { + private final Pseudocode pseudocode; + private final BindingContext bindingContext; + + private final Map> declaredVariablesInEachDeclaration = Maps.newHashMap(); + private final Map> usedVariablesInEachDeclaration = Maps.newHashMap(); + + private Map>> variableInitializersMap; + private Map>> variableStatusMap; + + public PseudocodeVariablesData(@NotNull Pseudocode pseudocode, @NotNull BindingContext bindingContext) { + this.pseudocode = pseudocode; + this.bindingContext = bindingContext; + } + + @NotNull + public Pseudocode getPseudocode() { + return pseudocode; + } + + @NotNull + public Set getUsedVariables(@NotNull Pseudocode pseudocode) { + Set usedVariables = usedVariablesInEachDeclaration.get(pseudocode); + if (usedVariables == null) { + final Set result = Sets.newHashSet(); + PseudocodeTraverser.traverse(pseudocode, true, new InstructionAnalyzeStrategy() { + @Override + public void execute(@NotNull Instruction instruction) { + VariableDescriptor variableDescriptor = PseudocodeUtil.extractVariableDescriptorIfAny(instruction, false, + bindingContext); + if (variableDescriptor != null) { + result.add(variableDescriptor); + } + } + }); + usedVariables = Collections.unmodifiableSet(result); + usedVariablesInEachDeclaration.put(pseudocode, usedVariables); + } + return usedVariables; + } + + @NotNull + public Set getDeclaredVariables(@NotNull Pseudocode pseudocode) { + Set declaredVariables = declaredVariablesInEachDeclaration.get(pseudocode); + if (declaredVariables == null) { + declaredVariables = Sets.newHashSet(); + for (Instruction instruction : pseudocode.getInstructions()) { + if (instruction instanceof VariableDeclarationInstruction) { + JetDeclaration variableDeclarationElement = ((VariableDeclarationInstruction) instruction).getVariableDeclarationElement(); + DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, variableDeclarationElement); + if (descriptor != null) { + assert descriptor instanceof VariableDescriptor; + declaredVariables.add((VariableDescriptor) descriptor); + } + } + } + declaredVariables = Collections.unmodifiableSet(declaredVariables); + declaredVariablesInEachDeclaration.put(pseudocode, declaredVariables); + } + return declaredVariables; + } + +// variable initializers + + @NotNull + public Map>> getVariableInitializers() { + if (variableInitializersMap == null) { + variableInitializersMap = getVariableInitializers(pseudocode); + } + return variableInitializersMap; + } + + @NotNull + private Map>> getVariableInitializers(@NotNull Pseudocode pseudocode) { + + Set usedVariables = getUsedVariables(pseudocode); + Set declaredVariables = getDeclaredVariables(pseudocode); + Map initialMap = Collections.emptyMap(); + final Map initialMapForStartInstruction = prepareInitializersMapForStartInstruction( + usedVariables, declaredVariables); + + Map>> variableInitializersMap = PseudocodeTraverser.collectData( + pseudocode, /* directOrder = */ true, /* lookInside = */ false, + initialMap, initialMapForStartInstruction, new PseudocodeTraverser.InstructionDataMergeStrategy>() { + @Override + public Edges> execute( + @NotNull Instruction instruction, @NotNull Collection> incomingEdgesData) { + + Map enterInstructionData = mergeIncomingEdgesDataForInitializers(incomingEdgesData); + Map exitInstructionData = + addVariableInitStateFromCurrentInstructionIfAny(instruction, enterInstructionData); + return Edges.create(enterInstructionData, exitInstructionData); + } + }); + + + for (LocalDeclarationInstruction localDeclarationInstruction : pseudocode.getLocalDeclarations()) { + Pseudocode localPseudocode = localDeclarationInstruction.getBody(); + Map>> initializersForLocalDeclaration = getVariableInitializers(localPseudocode); + + for (Instruction instruction : initializersForLocalDeclaration.keySet()) { + //todo + if (!variableInitializersMap.containsKey(instruction)) { + variableInitializersMap.put(instruction, initializersForLocalDeclaration.get(instruction)); + } + } + variableInitializersMap.putAll(initializersForLocalDeclaration); + } + return variableInitializersMap; + } + + @NotNull + private Map prepareInitializersMapForStartInstruction( + @NotNull Collection usedVariables, + @NotNull Collection declaredVariables) { + + Map initialMapForStartInstruction = Maps.newHashMap(); + VariableInitState initializedForExternalVariable = VariableInitState.create(true); + VariableInitState notInitializedForDeclaredVariable = VariableInitState.create(false); + + for (VariableDescriptor variable : usedVariables) { + if (declaredVariables.contains(variable)) { + initialMapForStartInstruction.put(variable, notInitializedForDeclaredVariable); + } + else { + initialMapForStartInstruction.put(variable, initializedForExternalVariable); + } + } + return initialMapForStartInstruction; + } + + @NotNull + private Map mergeIncomingEdgesDataForInitializers( + @NotNull Collection> incomingEdgesData) { + + Set variablesInScope = Sets.newHashSet(); + for (Map edgeData : incomingEdgesData) { + variablesInScope.addAll(edgeData.keySet()); + } + + Map enterInstructionData = Maps.newHashMap(); + for (VariableDescriptor variable : variablesInScope) { + Set edgesDataForVariable = Sets.newHashSet(); + for (Map edgeData : incomingEdgesData) { + VariableInitState initState = edgeData.get(variable); + if (initState != null) { + edgesDataForVariable.add(initState); + } + } + enterInstructionData.put(variable, VariableInitState.create(edgesDataForVariable)); + } + return enterInstructionData; + } + + @NotNull + private Map addVariableInitStateFromCurrentInstructionIfAny( + @NotNull Instruction instruction, @NotNull Map enterInstructionData) { + + if (!(instruction instanceof WriteValueInstruction) && !(instruction instanceof VariableDeclarationInstruction)) { + return enterInstructionData; + } + VariableDescriptor variable = PseudocodeUtil.extractVariableDescriptorIfAny(instruction, false, bindingContext); + if (variable == null) { + return enterInstructionData; + } + Map exitInstructionData = Maps.newHashMap(enterInstructionData); + if (instruction instanceof WriteValueInstruction) { + VariableInitState enterInitState = enterInstructionData.get(variable); + VariableInitState initializationAtThisElement = + VariableInitState.create(((WriteValueInstruction) instruction).getElement() instanceof JetProperty, enterInitState); + exitInstructionData.put(variable, initializationAtThisElement); + } + else { // instruction instanceof VariableDeclarationInstruction + VariableInitState enterInitState = enterInstructionData.get(variable); + if (enterInitState == null || !enterInitState.isInitialized || !enterInitState.isDeclared) { + boolean isInitialized = enterInitState != null && enterInitState.isInitialized; + VariableInitState variableDeclarationInfo = VariableInitState.create(isInitialized, true); + exitInstructionData.put(variable, variableDeclarationInfo); + } + } + return exitInstructionData; + } + +// variable use + + @NotNull + public Map>> getVariableUseStatusData() { + if (variableStatusMap == null) { + Map sinkInstructionData = Maps.newHashMap(); + for (VariableDescriptor usedVariable : usedVariablesInEachDeclaration.get(pseudocode)) { + sinkInstructionData.put(usedVariable, VariableUseState.UNUSED); + } + InstructionDataMergeStrategy> collectVariableUseStatusStrategy = new InstructionDataMergeStrategy>() { + @Override + public Edges> execute(@NotNull Instruction instruction, + @NotNull Collection> incomingEdgesData) { + + Map enterResult = Maps.newHashMap(); + for (Map edgeData : incomingEdgesData) { + for (Map.Entry entry : edgeData.entrySet()) { + VariableDescriptor variableDescriptor = entry.getKey(); + VariableUseState variableUseState = entry.getValue(); + enterResult.put(variableDescriptor, variableUseState.merge(enterResult.get(variableDescriptor))); + } + } + VariableDescriptor variableDescriptor = PseudocodeUtil.extractVariableDescriptorIfAny(instruction, true, + bindingContext); + if (variableDescriptor == null || + (!(instruction instanceof ReadValueInstruction) && !(instruction instanceof WriteValueInstruction))) { + return Edges.create(enterResult, enterResult); + } + Map exitResult = Maps.newHashMap(enterResult); + if (instruction instanceof ReadValueInstruction) { + exitResult.put(variableDescriptor, VariableUseState.LAST_READ); + } + else { //instruction instanceof WriteValueInstruction + VariableUseState variableUseState = enterResult.get(variableDescriptor); + if (variableUseState == null) { + variableUseState = VariableUseState.UNUSED; + } + switch (variableUseState) { + case UNUSED: + case ONLY_WRITTEN_NEVER_READ: + exitResult.put(variableDescriptor, VariableUseState.ONLY_WRITTEN_NEVER_READ); + break; + case LAST_WRITTEN: + case LAST_READ: + exitResult.put(variableDescriptor, VariableUseState.LAST_WRITTEN); + } + } + return Edges.create(enterResult, exitResult); + } + }; + variableStatusMap = PseudocodeTraverser.collectData(pseudocode, false, true, + Collections.emptyMap(), + sinkInstructionData, collectVariableUseStatusStrategy); + } + return variableStatusMap; + } + + public static class VariableInitState { + public final boolean isInitialized; + public final boolean isDeclared; + + private VariableInitState(boolean isInitialized, boolean isDeclared) { + this.isInitialized = isInitialized; + this.isDeclared = isDeclared; + } + + private static final VariableInitState VS_TT = new VariableInitState(true, true); + private static final VariableInitState VS_TF = new VariableInitState(true, false); + private static final VariableInitState VS_FT = new VariableInitState(false, true); + private static final VariableInitState VS_FF = new VariableInitState(false, false); + + + private static VariableInitState create(boolean isInitialized, boolean isDeclared) { + if (isInitialized) { + if (isDeclared) return VS_TT; + return VS_TF; + } + if (isDeclared) return VS_FT; + return VS_FF; + } + + private static VariableInitState create(boolean isInitialized) { + return create(isInitialized, false); + } + + private static VariableInitState create(boolean isDeclaredHere, @Nullable VariableInitState mergedEdgesData) { + return create(true, isDeclaredHere || (mergedEdgesData != null && mergedEdgesData.isDeclared)); + } + + private static VariableInitState create(@NotNull Set edgesData) { + boolean isInitialized = true; + boolean isDeclared = true; + for (VariableInitState edgeData : edgesData) { + if (!edgeData.isInitialized) { + isInitialized = false; + } + if (!edgeData.isDeclared) { + isDeclared = false; + } + } + return create(isInitialized, isDeclared); + } + } + + public static enum VariableUseState { + LAST_READ(3), + LAST_WRITTEN(2), + ONLY_WRITTEN_NEVER_READ(1), + UNUSED(0); + + private final int importance; + + VariableUseState(int importance) { + this.importance = importance; + } + + private VariableUseState merge(@Nullable VariableUseState variableUseState) { + if (variableUseState == null || importance > variableUseState.importance) return this; + return variableUseState; + } + + public static boolean isUsed(@Nullable VariableUseState variableUseState) { + return variableUseState != null && variableUseState != UNUSED; + } + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java index db3dcea5ced..f888d1711ef 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java @@ -35,12 +35,6 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd private final Stack allBlocks = new Stack(); - private final JetPseudocodeTrace trace; - - public JetControlFlowInstructionsGenerator(JetPseudocodeTrace trace) { - this.trace = trace; - } - private void pushBuilder(JetElement scopingElement, JetElement subroutine) { JetControlFlowInstructionsGeneratorWorker worker = new JetControlFlowInstructionsGeneratorWorker(scopingElement, subroutine); builders.push(worker); @@ -49,7 +43,6 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd private JetControlFlowInstructionsGeneratorWorker popBuilder(@NotNull JetElement element) { JetControlFlowInstructionsGeneratorWorker worker = builders.pop(); - trace.recordControlFlowData(element, worker.getPseudocode()); if (!builders.isEmpty()) { builder = builders.peek(); } @@ -72,7 +65,7 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd } @Override - public void exitSubroutine(@NotNull JetDeclaration subroutine) { + public Pseudocode exitSubroutine(@NotNull JetDeclaration subroutine) { super.exitSubroutine(subroutine); JetControlFlowInstructionsGeneratorWorker worker = popBuilder(subroutine); if (!builders.empty()) { @@ -80,32 +73,29 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd LocalDeclarationInstruction instruction = new LocalDeclarationInstruction(subroutine, worker.getPseudocode()); builder.add(instruction); } + return worker.getPseudocode(); } private class JetControlFlowInstructionsGeneratorWorker implements JetControlFlowBuilder { - private final Pseudocode pseudocode; + private final PseudocodeImpl pseudocode; private final Label error; private final Label sink; private final JetElement returnSubroutine; private JetControlFlowInstructionsGeneratorWorker(@NotNull JetElement scopingElement, @NotNull JetElement returnSubroutine) { - this.pseudocode = new Pseudocode(scopingElement); + this.pseudocode = new PseudocodeImpl(scopingElement); this.error = pseudocode.createLabel("error"); this.sink = pseudocode.createLabel("sink"); this.returnSubroutine = returnSubroutine; } - public Pseudocode getPseudocode() { + public PseudocodeImpl getPseudocode() { return pseudocode; } private void add(@NotNull Instruction instruction) { pseudocode.addInstruction(instruction); - if (instruction instanceof JetElementInstruction) { - JetElementInstruction elementInstruction = (JetElementInstruction) instruction; - trace.recordRepresentativeInstruction(elementInstruction.getElement(), instruction); - } } @NotNull @@ -127,7 +117,7 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd loopInfo.push(blockInfo); elementToBlockInfo.put(expression, blockInfo); allBlocks.push(blockInfo); - trace.recordLoopInfo(expression, blockInfo); + pseudocode.recordLoopInfo(expression, blockInfo); return blockInfo; } @@ -202,7 +192,7 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd } @Override - public void exitSubroutine(@NotNull JetDeclaration subroutine) { + public Pseudocode exitSubroutine(@NotNull JetDeclaration subroutine) { bindLabel(getExitPoint(subroutine)); pseudocode.addExitInstruction(new SubroutineExitInstruction(subroutine, "")); bindLabel(error); @@ -211,6 +201,7 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd pseudocode.addSinkInstruction(new SubroutineSinkInstruction(subroutine, "")); elementToBlockInfo.remove(subroutine); allBlocks.pop(); + return null; } @Override diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/JetPseudocodeTrace.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/JetPseudocodeTrace.java deleted file mode 100644 index b3149aa1090..00000000000 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/JetPseudocodeTrace.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2010-2012 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.lang.cfg.pseudocode; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.cfg.LoopInfo; -import org.jetbrains.jet.lang.psi.JetElement; -import org.jetbrains.jet.lang.psi.JetExpression; - -/** - * @author abreslav - */ -public interface JetPseudocodeTrace { - - JetPseudocodeTrace EMPTY = new JetPseudocodeTrace() { - @Override - public void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode) { - } - - @Override - public void recordRepresentativeInstruction(@NotNull JetElement element, @NotNull Instruction instruction) { - - } - - @Override - public void close() { - } - - @Override - public void recordLoopInfo(JetExpression expression, LoopInfo blockInfo) { - - } - }; - - void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode); - void recordRepresentativeInstruction(@NotNull JetElement element, @NotNull Instruction instruction); - void close(); - - void recordLoopInfo(JetExpression expression, LoopInfo blockInfo); -} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/LocalDeclarationInstruction.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/LocalDeclarationInstruction.java index 990c2142c9c..fd8639d94f9 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/LocalDeclarationInstruction.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/LocalDeclarationInstruction.java @@ -19,6 +19,7 @@ package org.jetbrains.jet.lang.cfg.pseudocode; import com.google.common.collect.Lists; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.psi.JetDeclaration; +import org.jetbrains.jet.lang.psi.JetElement; import java.util.ArrayList; import java.util.Collection; @@ -40,6 +41,12 @@ public class LocalDeclarationInstruction extends InstructionWithNext { return body; } + @NotNull + @Override + public JetDeclaration getElement() { + return (JetDeclaration) super.getElement(); + } + @NotNull @Override public Collection getNextInstructions() { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/Pseudocode.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/Pseudocode.java index 47dcbea39ea..8394b6725ce 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/Pseudocode.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/Pseudocode.java @@ -16,343 +16,37 @@ package org.jetbrains.jet.lang.cfg.pseudocode; -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.cfg.Label; import org.jetbrains.jet.lang.psi.JetElement; -import java.util.ArrayList; -import java.util.Collection; import java.util.List; import java.util.Set; /** -* @author abreslav -*/ -public class Pseudocode { - - public class PseudocodeLabel implements Label { - private final String name; - private Integer targetInstructionIndex; - - - private PseudocodeLabel(String name) { - this.name = name; - } - - @Override - public String getName() { - return name; - } - - @Override - public String toString() { - return name; - } - - public Integer getTargetInstructionIndex() { - return targetInstructionIndex; - } - - public void setTargetInstructionIndex(int targetInstructionIndex) { - this.targetInstructionIndex = targetInstructionIndex; - } - - @Nullable - private List resolve() { - assert targetInstructionIndex != null; - return mutableInstructionList.subList(getTargetInstructionIndex(), mutableInstructionList.size()); - } - - public Instruction resolveToInstruction() { - assert targetInstructionIndex != null; - return mutableInstructionList.get(targetInstructionIndex); - } - - } - - private final List mutableInstructionList = new ArrayList(); - private final List instructions = new ArrayList(); - private List deadInstructions; - - private final List labels = new ArrayList(); - private final List allowedDeadLabels = new ArrayList(); - private final List stopAllowDeadLabels = new ArrayList(); - - private final JetElement correspondingElement; - private SubroutineExitInstruction exitInstruction; - private SubroutineSinkInstruction sinkInstruction; - private SubroutineExitInstruction errorInstruction; - private boolean postPrecessed = false; - - public Pseudocode(JetElement correspondingElement) { - this.correspondingElement = correspondingElement; - } - - public JetElement getCorrespondingElement() { - return correspondingElement; - } - - public PseudocodeLabel createLabel(String name) { - PseudocodeLabel label = new PseudocodeLabel(name); - labels.add(label); - return label; - } - - public void allowDead(Label label) { - allowedDeadLabels.add((PseudocodeLabel) label); - } - - public void stopAllowDead(Label label) { - stopAllowDeadLabels.add((PseudocodeLabel) label); - } + * @author svtk + */ +public interface Pseudocode { + @NotNull + JetElement getCorrespondingElement(); @NotNull - public List getInstructions() { - return instructions; - } - - @Deprecated //for tests only - @NotNull - public List getMutableInstructionList() { - return mutableInstructionList; - } - - @NotNull - public List getDeadInstructions() { - if (deadInstructions != null) { - return deadInstructions; - } - deadInstructions = Lists.newArrayList(); - Collection allowedDeadInstructions = collectAllowedDeadInstructions(); - - for (Instruction instruction : mutableInstructionList) { - if (((InstructionImpl)instruction).isDead()) { - if (!allowedDeadInstructions.contains(instruction)) { - deadInstructions.add(instruction); - } - } - } - return deadInstructions; - } - - @Deprecated //for tests only - @NotNull - public List getLabels() { - return labels; - } - - public void addExitInstruction(SubroutineExitInstruction exitInstruction) { - addInstruction(exitInstruction); - assert this.exitInstruction == null; - this.exitInstruction = exitInstruction; - } - - public void addSinkInstruction(SubroutineSinkInstruction sinkInstruction) { - addInstruction(sinkInstruction); - assert this.sinkInstruction == null; - this.sinkInstruction = sinkInstruction; - } - - public void addErrorInstruction(SubroutineExitInstruction errorInstruction) { - addInstruction(errorInstruction); - assert this.errorInstruction == null; - this.errorInstruction = errorInstruction; - } - - public void addInstruction(Instruction instruction) { - mutableInstructionList.add(instruction); - instruction.setOwner(this); - } + Set getLocalDeclarations(); @NotNull - public SubroutineExitInstruction getExitInstruction() { - return exitInstruction; - } + List getInstructions(); @NotNull - public SubroutineSinkInstruction getSinkInstruction() { - return sinkInstruction; - } - + List getReversedInstructions(); @NotNull - public SubroutineEnterInstruction getEnterInstruction() { - return (SubroutineEnterInstruction) mutableInstructionList.get(0); - } - - public void bindLabel(Label label) { - ((PseudocodeLabel) label).setTargetInstructionIndex(mutableInstructionList.size()); - } - - public void postProcess() { - if (postPrecessed) return; - postPrecessed = true; - for (int i = 0, instructionsSize = mutableInstructionList.size(); i < instructionsSize; i++) { - processInstruction(mutableInstructionList.get(i), i); - } - getExitInstruction().setSink(getSinkInstruction()); - Set reachableInstructions = collectReachableInstructions(); - for (Instruction instruction : mutableInstructionList) { - if (reachableInstructions.contains(instruction)) { - instructions.add(instruction); - } - } - markDeadInstructions(); - } - - private void processInstruction(Instruction instruction, final int currentPosition) { - instruction.accept(new InstructionVisitor() { - @Override - public void visitInstructionWithNext(InstructionWithNext instruction) { - instruction.setNext(getNextPosition(currentPosition)); - } - - @Override - public void visitJump(AbstractJumpInstruction instruction) { - instruction.setResolvedTarget(getJumpTarget(instruction.getTargetLabel())); - } - - @Override - public void visitNondeterministicJump(NondeterministicJumpInstruction instruction) { - instruction.setNext(getNextPosition(currentPosition)); - List