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    }