001 /*
002 * Copyright 2010-2015 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
017 package org.jetbrains.kotlin.resolve.calls.smartcasts;
018
019 import org.jetbrains.annotations.NotNull;
020 import org.jetbrains.annotations.Nullable;
021 import org.jetbrains.kotlin.types.ErrorUtils;
022 import org.jetbrains.kotlin.types.JetType;
023 import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
024
025 /**
026 * This class describes an arbitrary object which has some value in data flow analysis.
027 * In general case it's some r-value.
028 */
029 public class DataFlowValue {
030
031 public static final DataFlowValue NULL = new DataFlowValue(new Object(), KotlinBuiltIns.getInstance().getNullableNothingType(), false, false, Nullability.NULL);
032 public static final DataFlowValue NULLABLE = new DataFlowValue(new Object(), KotlinBuiltIns.getInstance().getNullableAnyType(), false, false, Nullability.UNKNOWN);
033 public static final DataFlowValue ERROR = new DataFlowValue(new Object(), ErrorUtils.createErrorType("Error type for data flow"), false, false, Nullability.IMPOSSIBLE);
034
035 private final boolean stableIdentifier;
036 private final boolean uncapturedLocalVariable;
037 private final JetType type;
038 private final Object id;
039 private final Nullability immanentNullability;
040
041 // Use DataFlowValueFactory
042 /*package*/ DataFlowValue(Object id, JetType type, boolean stableIdentifier, boolean uncapturedLocalVariable, Nullability immanentNullability) {
043 assert !stableIdentifier || !uncapturedLocalVariable :
044 "data flow value for object " + id + " cannot be together a stable identifier and an uncaptured local variable";
045 this.stableIdentifier = stableIdentifier;
046 this.uncapturedLocalVariable = uncapturedLocalVariable;
047 this.type = type;
048 this.id = id;
049 this.immanentNullability = immanentNullability;
050 }
051
052 @Nullable
053 public Object getId() {
054 return id;
055 }
056
057 @NotNull
058 public Nullability getImmanentNullability() {
059 return immanentNullability;
060 }
061
062 /**
063 * Stable identifier is a non-literal value that is statically known to be immutable
064 *
065 * NB: this function is no longer public!
066 * If you are checking for a possible smart cast, probably you need isPredictable() instead
067 */
068 private boolean isStableIdentifier() {
069 return stableIdentifier;
070 }
071
072 /**
073 * Identifier is considered a local variable here if it's mutable (var), local and not captured in a closure
074 */
075 public boolean isUncapturedLocalVariable() {
076 return uncapturedLocalVariable;
077 }
078
079 /**
080 * Both stable identifiers and uncaptured local variables are considered "predictable".
081 * Predictable means here we do not expect some sudden change of their values,
082 * like accessing mutable properties in another thread or mutable variables from closures.
083 */
084 public boolean isPredictable() {
085 return stableIdentifier || uncapturedLocalVariable;
086 }
087
088 @NotNull
089 public JetType getType() {
090 return type;
091 }
092
093 @Override
094 public boolean equals(Object o) {
095 if (this == o) return true;
096 if (o == null || getClass() != o.getClass()) return false;
097
098 DataFlowValue that = (DataFlowValue) o;
099
100 if (stableIdentifier != that.stableIdentifier) return false;
101 if (id != null ? !id.equals(that.id) : that.id != null) return false;
102 if (type != null ? !type.equals(that.type) : that.type != null) return false;
103
104 return true;
105 }
106
107 @Override
108 public String toString() {
109 return (stableIdentifier ? "stable " : "unstable ") + (id == null ? null : id.toString()) + " " + immanentNullability;
110 }
111
112 @Override
113 public int hashCode() {
114 int result = (stableIdentifier ? 1 : 0);
115 result = 31 * result + (type != null ? type.hashCode() : 0);
116 result = 31 * result + (id != null ? id.hashCode() : 0);
117 return result;
118 }
119 }