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;
018    
019    import com.google.common.collect.ImmutableMap;
020    import com.google.common.collect.Lists;
021    import com.google.common.collect.Maps;
022    import kotlin.jvm.functions.Function3;
023    import org.jetbrains.annotations.NotNull;
024    import org.jetbrains.annotations.Nullable;
025    import org.jetbrains.annotations.TestOnly;
026    import org.jetbrains.kotlin.diagnostics.Diagnostic;
027    import org.jetbrains.kotlin.psi.JetExpression;
028    import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics;
029    import org.jetbrains.kotlin.resolve.diagnostics.MutableDiagnosticsWithSuppression;
030    import org.jetbrains.kotlin.types.JetType;
031    import org.jetbrains.kotlin.types.expressions.JetTypeInfo;
032    import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryPackage;
033    import org.jetbrains.kotlin.util.slicedMap.*;
034    
035    import java.util.Collection;
036    import java.util.List;
037    import java.util.Map;
038    
039    public class DelegatingBindingTrace implements BindingTrace {
040        @SuppressWarnings("ConstantConditions")
041        private final MutableSlicedMap map = BindingTraceContext.TRACK_REWRITES ? new TrackingSlicedMap(BindingTraceContext.TRACK_WITH_STACK_TRACES) : SlicedMapImpl.create();
042    
043        private final BindingContext parentContext;
044        private final String name;
045        private final MutableDiagnosticsWithSuppression mutableDiagnostics;
046    
047        private final BindingContext bindingContext = new BindingContext() {
048            @NotNull
049            @Override
050            public Diagnostics getDiagnostics() {
051                return mutableDiagnostics;
052            }
053    
054            @Override
055            public <K, V> V get(ReadOnlySlice<K, V> slice, K key) {
056                return DelegatingBindingTrace.this.get(slice, key);
057            }
058    
059    
060            @Nullable
061            @Override
062            public JetType getType(@NotNull JetExpression expression) {
063                return DelegatingBindingTrace.this.getType(expression);
064            }
065    
066            @NotNull
067            @Override
068            public <K, V> Collection<K> getKeys(WritableSlice<K, V> slice) {
069                return DelegatingBindingTrace.this.getKeys(slice);
070    
071            }
072    
073            @NotNull
074            @TestOnly
075            @Override
076            public <K, V> ImmutableMap<K, V> getSliceContents(@NotNull ReadOnlySlice<K, V> slice) {
077                Map<K, V> result = Maps.newHashMap();
078                result.putAll(parentContext.getSliceContents(slice));
079                result.putAll(map.getSliceContents(slice));
080                return ImmutableMap.copyOf(result);
081            }
082        };
083    
084        public DelegatingBindingTrace(BindingContext parentContext, String debugName) {
085            this.parentContext = parentContext;
086            this.name = debugName;
087            this.mutableDiagnostics = new MutableDiagnosticsWithSuppression(bindingContext, parentContext.getDiagnostics());
088        }
089    
090        public DelegatingBindingTrace(BindingContext parentContext, String debugName, @Nullable Object resolutionSubjectForMessage) {
091            this(parentContext, AnalyzingUtils.formDebugNameForBindingTrace(debugName, resolutionSubjectForMessage));
092        }
093    
094        @Override
095        @NotNull
096        public BindingContext getBindingContext() {
097            return bindingContext;
098        }
099    
100        @Override
101        public <K, V> void record(WritableSlice<K, V> slice, K key, V value) {
102            map.put(slice, key, value);
103        }
104    
105        @Override
106        public <K> void record(WritableSlice<K, Boolean> slice, K key) {
107            record(slice, key, true);
108        }
109    
110        @Override
111        public <K, V> V get(ReadOnlySlice<K, V> slice, K key) {
112            V value = map.get(slice, key);
113            if (slice instanceof Slices.SetSlice) {
114                assert value != null;
115                if (value.equals(true)) return value;
116            }
117            else if (value != null) {
118                return value;
119            }
120    
121            return parentContext.get(slice, key);
122        }
123    
124        @NotNull
125        @Override
126        public <K, V> Collection<K> getKeys(WritableSlice<K, V> slice) {
127            Collection<K> keys = map.getKeys(slice);
128            Collection<K> fromParent = parentContext.getKeys(slice);
129            if (keys.isEmpty()) return fromParent;
130            if (fromParent.isEmpty()) return keys;
131    
132            List<K> result = Lists.newArrayList(keys);
133            result.addAll(fromParent);
134            return result;
135        }
136    
137        @Nullable
138        @Override
139        public JetType getType(@NotNull JetExpression expression) {
140            JetTypeInfo typeInfo = get(BindingContext.EXPRESSION_TYPE_INFO, expression);
141            return typeInfo != null ? typeInfo.getType() : null;
142        }
143    
144        @Override
145        public void recordType(@NotNull JetExpression expression, @Nullable JetType type) {
146            JetTypeInfo typeInfo = get(BindingContext.EXPRESSION_TYPE_INFO, expression);
147            if (typeInfo == null) {
148                typeInfo = TypeInfoFactoryPackage.createTypeInfo(type);
149            }
150            else {
151                typeInfo = typeInfo.replaceType(type);
152            }
153            record(BindingContext.EXPRESSION_TYPE_INFO, expression, typeInfo);
154        }
155    
156        public void addAllMyDataTo(@NotNull BindingTrace trace) {
157            addAllMyDataTo(trace, null, true);
158        }
159    
160        public void moveAllMyDataTo(@NotNull BindingTrace trace) {
161            addAllMyDataTo(trace, null, true);
162            clear();
163        }
164    
165        public void addAllMyDataTo(@NotNull final BindingTrace trace, @Nullable final TraceEntryFilter filter, boolean commitDiagnostics) {
166            map.forEach(new Function3<WritableSlice, Object, Object, Void>() {
167                @Override
168                public Void invoke(WritableSlice slice, Object key, Object value) {
169                    if (filter == null || filter.accept(slice, key)) {
170                        trace.record(slice, key, value);
171                    }
172    
173                    return null;
174                }
175            });
176    
177            if (!commitDiagnostics) return;
178    
179            for (Diagnostic diagnostic : mutableDiagnostics.getOwnDiagnostics()) {
180                if (filter == null || filter.accept(null, diagnostic.getPsiElement())) {
181                    trace.report(diagnostic);
182                }
183            }
184        }
185    
186        public void clear() {
187            map.clear();
188            mutableDiagnostics.clear();
189        }
190    
191        @Override
192        public void report(@NotNull Diagnostic diagnostic) {
193            mutableDiagnostics.report(diagnostic);
194        }
195    
196        @Override
197        public String toString() {
198            return name;
199        }
200    }