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 }