001/* 002 * Copyright 2010-2013 JetBrains s.r.o. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.jetbrains.jet.lang.resolve.calls.autocasts; 018 019import com.intellij.openapi.util.Pair; 020import org.jetbrains.annotations.NotNull; 021import org.jetbrains.annotations.Nullable; 022import org.jetbrains.jet.JetNodeTypes; 023import org.jetbrains.jet.lang.descriptors.*; 024import org.jetbrains.jet.lang.psi.*; 025import org.jetbrains.jet.lang.resolve.BindingContext; 026import org.jetbrains.jet.lang.resolve.JetModuleUtil; 027import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; 028import org.jetbrains.jet.lang.resolve.scopes.receivers.*; 029import org.jetbrains.jet.lang.types.JetType; 030import org.jetbrains.jet.lang.types.TypeUtils; 031import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; 032 033import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; 034import static org.jetbrains.jet.lang.resolve.BindingContext.RESOLVED_CALL; 035 036public class DataFlowValueFactory { 037 public static final DataFlowValueFactory INSTANCE = new DataFlowValueFactory(); 038 039 private DataFlowValueFactory() {} 040 041 @NotNull 042 public DataFlowValue createDataFlowValue(@NotNull JetExpression expression, @NotNull JetType type, @NotNull BindingContext bindingContext) { 043 if (expression instanceof JetConstantExpression) { 044 JetConstantExpression constantExpression = (JetConstantExpression) expression; 045 if (constantExpression.getNode().getElementType() == JetNodeTypes.NULL) return DataFlowValue.NULL; 046 } 047 if (TypeUtils.equalTypes(type, KotlinBuiltIns.getInstance().getNullableNothingType())) return DataFlowValue.NULL; // 'null' is the only inhabitant of 'Nothing?' 048 IdentifierInfo result = getIdForStableIdentifier(expression, bindingContext); 049 return new DataFlowValue(result.id == null ? expression : result.id, type, result.isStable, getImmanentNullability(type)); 050 } 051 052 @NotNull 053 public DataFlowValue createDataFlowValue(@NotNull ThisReceiver receiver) { 054 JetType type = receiver.getType(); 055 return new DataFlowValue(receiver, type, true, getImmanentNullability(type)); 056 } 057 058 @NotNull 059 public DataFlowValue createDataFlowValue(@NotNull VariableDescriptor variableDescriptor) { 060 JetType type = variableDescriptor.getType(); 061 return new DataFlowValue(variableDescriptor, type, isStableVariable(variableDescriptor), getImmanentNullability(type)); 062 } 063 064 @NotNull 065 public DataFlowValue createDataFlowValue(@NotNull ReceiverValue receiverValue, @NotNull BindingContext bindingContext) { 066 return receiverValue.accept(new ReceiverValueVisitor<DataFlowValue, BindingContext>() { 067 @Override 068 public DataFlowValue visitNoReceiver(ReceiverValue noReceiver, BindingContext data) { 069 throw new IllegalArgumentException("No DataFlowValue exists for ReceiverValue.NO_RECEIVER"); 070 } 071 072 @Override 073 public DataFlowValue visitExtensionReceiver(ExtensionReceiver receiver, BindingContext data) { 074 return createDataFlowValue(receiver); 075 } 076 077 @Override 078 public DataFlowValue visitExpressionReceiver(ExpressionReceiver receiver, BindingContext bindingContext) { 079 return createDataFlowValue(receiver.getExpression(), receiver.getType(), bindingContext); 080 } 081 082 @Override 083 public DataFlowValue visitClassReceiver(ClassReceiver receiver, BindingContext data) { 084 return createDataFlowValue(receiver); 085 } 086 087 @Override 088 public DataFlowValue visitTransientReceiver(TransientReceiver receiver, BindingContext data) { 089 return createTransientDataFlowValue(receiver); 090 } 091 092 @Override 093 public DataFlowValue visitScriptReceiver(ScriptReceiver receiver, BindingContext data) { 094 return createTransientDataFlowValue(receiver); 095 } 096 097 @NotNull 098 private DataFlowValue createTransientDataFlowValue(ReceiverValue receiver) { 099 JetType type = receiver.getType(); 100 boolean nullable = type.isNullable() || TypeUtils.hasNullableSuperType(type); 101 return new DataFlowValue(receiver, type, nullable, Nullability.NOT_NULL); 102 } 103 }, bindingContext); 104 } 105 106 private Nullability getImmanentNullability(JetType type) { 107 return type.isNullable() || TypeUtils.hasNullableSuperType(type) ? Nullability.UNKNOWN : Nullability.NOT_NULL; 108 } 109 110 private static class IdentifierInfo { 111 public final Object id; 112 public final boolean isStable; 113 public final boolean isNamespace; 114 115 private IdentifierInfo(Object id, boolean isStable, boolean isNamespace) { 116 this.id = id; 117 this.isStable = isStable; 118 this.isNamespace = isNamespace; 119 } 120 } 121 122 private static final IdentifierInfo NO_IDENTIFIER_INFO = new IdentifierInfo(null, false, false) { 123 @Override 124 public String toString() { 125 return "NO_IDENTIFIER_INFO"; 126 } 127 }; 128 129 @NotNull 130 private static IdentifierInfo createInfo(Object id, boolean isStable) { 131 return new IdentifierInfo(id, isStable, false); 132 } 133 134 @NotNull 135 private static IdentifierInfo createNamespaceInfo(Object id) { 136 return new IdentifierInfo(id, true, true); 137 } 138 139 @NotNull 140 private static IdentifierInfo combineInfo(@Nullable IdentifierInfo receiverInfo, @NotNull IdentifierInfo selectorInfo) { 141 if (selectorInfo.id == null) { 142 return NO_IDENTIFIER_INFO; 143 } 144 if (receiverInfo == null || receiverInfo == NO_IDENTIFIER_INFO || receiverInfo.isNamespace) { 145 return selectorInfo; 146 } 147 return createInfo(Pair.create(receiverInfo.id, selectorInfo.id), receiverInfo.isStable && selectorInfo.isStable); 148 } 149 150 @NotNull 151 private static IdentifierInfo getIdForStableIdentifier( 152 @Nullable JetExpression expression, 153 @NotNull BindingContext bindingContext 154 ) { 155 if (expression instanceof JetParenthesizedExpression) { 156 JetParenthesizedExpression parenthesizedExpression = (JetParenthesizedExpression) expression; 157 JetExpression innerExpression = parenthesizedExpression.getExpression(); 158 159 return getIdForStableIdentifier(innerExpression, bindingContext); 160 } 161 else if (expression instanceof JetQualifiedExpression) { 162 JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) expression; 163 JetExpression receiverExpression = qualifiedExpression.getReceiverExpression(); 164 JetExpression selectorExpression = qualifiedExpression.getSelectorExpression(); 165 IdentifierInfo receiverId = getIdForStableIdentifier(receiverExpression, bindingContext); 166 IdentifierInfo selectorId = getIdForStableIdentifier(selectorExpression, bindingContext); 167 168 return combineInfo(receiverId, selectorId); 169 } 170 if (expression instanceof JetSimpleNameExpression) { 171 return getIdForSimpleNameExpression((JetSimpleNameExpression) expression, bindingContext); 172 } 173 else if (expression instanceof JetThisExpression) { 174 JetThisExpression thisExpression = (JetThisExpression) expression; 175 DeclarationDescriptor declarationDescriptor = bindingContext.get(REFERENCE_TARGET, thisExpression.getInstanceReference()); 176 177 return getIdForThisReceiver(declarationDescriptor); 178 } 179 else if (expression instanceof JetRootNamespaceExpression) { 180 return createNamespaceInfo(JetModuleUtil.getRootNamespaceType(expression)); 181 } 182 return NO_IDENTIFIER_INFO; 183 } 184 185 @NotNull 186 private static IdentifierInfo getIdForSimpleNameExpression( 187 @NotNull JetSimpleNameExpression simpleNameExpression, 188 @NotNull BindingContext bindingContext 189 ) { 190 DeclarationDescriptor declarationDescriptor = bindingContext.get(REFERENCE_TARGET, simpleNameExpression); 191 if (declarationDescriptor instanceof VariableDescriptor) { 192 ResolvedCall<?> resolvedCall = bindingContext.get(RESOLVED_CALL, simpleNameExpression); 193 // todo uncomment assert 194 // for now it fails for resolving 'invoke' convention, return it after 'invoke' algorithm changes 195 // assert resolvedCall != null : "Cannot create right identifier info if the resolved call is not known yet for " + declarationDescriptor; 196 197 IdentifierInfo receiverInfo = resolvedCall != null ? getIdForImplicitReceiver(resolvedCall.getThisObject(), simpleNameExpression) : null; 198 199 VariableDescriptor variableDescriptor = (VariableDescriptor) declarationDescriptor; 200 return combineInfo(receiverInfo, createInfo(variableDescriptor, isStableVariable(variableDescriptor))); 201 } 202 if (declarationDescriptor instanceof NamespaceDescriptor) { 203 return createNamespaceInfo(declarationDescriptor); 204 } 205 return NO_IDENTIFIER_INFO; 206 } 207 208 @Nullable 209 private static IdentifierInfo getIdForImplicitReceiver(@NotNull ReceiverValue receiverValue, @Nullable final JetExpression expression) { 210 return receiverValue.accept(new ReceiverValueVisitor<IdentifierInfo, Void>() { 211 212 @Override 213 public IdentifierInfo visitNoReceiver(ReceiverValue noReceiver, Void data) { 214 return null; 215 } 216 217 @Override 218 public IdentifierInfo visitTransientReceiver(TransientReceiver receiver, Void data) { 219 assert false: "Transient receiver is implicit for an explicit expression: " + expression + ". Receiver: " + receiver; 220 return null; 221 } 222 223 @Override 224 public IdentifierInfo visitExtensionReceiver(ExtensionReceiver receiver, Void data) { 225 return getIdForThisReceiver(receiver); 226 } 227 228 @Override 229 public IdentifierInfo visitExpressionReceiver(ExpressionReceiver receiver, Void data) { 230 // there is an explicit "this" expression and it was analyzed earlier 231 return null; 232 } 233 234 @Override 235 public IdentifierInfo visitClassReceiver(ClassReceiver receiver, Void data) { 236 return getIdForThisReceiver(receiver); 237 } 238 239 @Override 240 public IdentifierInfo visitScriptReceiver(ScriptReceiver receiver, Void data) { 241 return getIdForThisReceiver(receiver); 242 } 243 }, null); 244 } 245 246 @NotNull 247 private static IdentifierInfo getIdForThisReceiver(@NotNull ThisReceiver thisReceiver) { 248 return getIdForThisReceiver(thisReceiver.getDeclarationDescriptor()); 249 } 250 251 @NotNull 252 private static IdentifierInfo getIdForThisReceiver(@Nullable DeclarationDescriptor descriptorOfThisReceiver) { 253 if (descriptorOfThisReceiver instanceof CallableDescriptor) { 254 ReceiverParameterDescriptor receiverParameter = ((CallableDescriptor) descriptorOfThisReceiver).getReceiverParameter(); 255 assert receiverParameter != null : "'This' refers to the callable member without a receiver parameter: " + descriptorOfThisReceiver; 256 return createInfo(receiverParameter.getValue(), true); 257 } 258 if (descriptorOfThisReceiver instanceof ClassDescriptor) { 259 return createInfo(((ClassDescriptor) descriptorOfThisReceiver).getThisAsReceiverParameter().getValue(), true); 260 } 261 return NO_IDENTIFIER_INFO; 262 } 263 264 public static boolean isStableVariable(@NotNull VariableDescriptor variableDescriptor) { 265 if (variableDescriptor.isVar()) return false; 266 if (variableDescriptor instanceof PropertyDescriptor) { 267 PropertyDescriptor propertyDescriptor = (PropertyDescriptor) variableDescriptor; 268 if (!invisibleFromOtherModules(propertyDescriptor)) return false; 269 if (!isFinal(propertyDescriptor)) return false; 270 if (!hasDefaultGetter(propertyDescriptor)) return false; 271 } 272 return true; 273 } 274 275 private static boolean isFinal(PropertyDescriptor propertyDescriptor) { 276 DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration(); 277 if (containingDeclaration instanceof ClassDescriptor) { 278 ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration; 279 if (classDescriptor.getModality().isOverridable() && propertyDescriptor.getModality().isOverridable()) return false; 280 } 281 else { 282 if (propertyDescriptor.getModality().isOverridable()) { 283 throw new IllegalStateException("Property outside a class must not be overridable: " + propertyDescriptor.getName()); 284 } 285 } 286 return true; 287 } 288 289 private static boolean invisibleFromOtherModules(@NotNull DeclarationDescriptorWithVisibility descriptor) { 290 if (Visibilities.INVISIBLE_FROM_OTHER_MODULES.contains(descriptor.getVisibility())) return true; 291 292 DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); 293 if (!(containingDeclaration instanceof DeclarationDescriptorWithVisibility)) { 294 return false; 295 } 296 297 return invisibleFromOtherModules((DeclarationDescriptorWithVisibility) containingDeclaration); 298 } 299 300 private static boolean hasDefaultGetter(PropertyDescriptor propertyDescriptor) { 301 PropertyGetterDescriptor getter = propertyDescriptor.getGetter(); 302 return getter == null || getter.isDefault(); 303 } 304}