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
017 package org.jetbrains.jet.lang.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 org.jetbrains.annotations.NotNull;
023 import org.jetbrains.annotations.Nullable;
024 import org.jetbrains.annotations.TestOnly;
025 import org.jetbrains.jet.lang.diagnostics.Diagnostic;
026 import org.jetbrains.jet.util.slicedmap.*;
027
028 import java.util.ArrayList;
029 import java.util.Collection;
030 import java.util.List;
031 import java.util.Map;
032
033 public class DelegatingBindingTrace implements BindingTrace {
034 @SuppressWarnings("ConstantConditions")
035 private final MutableSlicedMap map = BindingTraceContext.TRACK_REWRITES ? new TrackingSlicedMap(BindingTraceContext.TRACK_WITH_STACK_TRACES) : SlicedMapImpl.create();
036
037 private final BindingContext parentContext;
038 private final List<Diagnostic> diagnostics = Lists.newArrayList();
039 private final String name;
040
041 private final BindingContext bindingContext = new BindingContext() {
042 @NotNull
043 @Override
044 public Diagnostics getDiagnostics() {
045 ArrayList<Diagnostic> mergedDiagnostics = new ArrayList<Diagnostic>(diagnostics);
046 mergedDiagnostics.addAll(parentContext.getDiagnostics().noSuppression().all());
047 return new DiagnosticsWithSuppression(this, mergedDiagnostics);
048 }
049
050 @Override
051 public <K, V> V get(ReadOnlySlice<K, V> slice, K key) {
052 return DelegatingBindingTrace.this.get(slice, key);
053 }
054
055 @NotNull
056 @Override
057 public <K, V> Collection<K> getKeys(WritableSlice<K, V> slice) {
058 return DelegatingBindingTrace.this.getKeys(slice);
059
060 }
061
062 @NotNull
063 @TestOnly
064 @Override
065 public <K, V> ImmutableMap<K, V> getSliceContents(@NotNull ReadOnlySlice<K, V> slice) {
066 Map<K, V> result = Maps.newHashMap();
067 result.putAll(parentContext.getSliceContents(slice));
068 result.putAll(map.getSliceContents(slice));
069 return ImmutableMap.copyOf(result);
070 }
071 };
072
073 public DelegatingBindingTrace(BindingContext parentContext, String debugName) {
074 this.parentContext = parentContext;
075 this.name = debugName;
076 }
077
078 public DelegatingBindingTrace(BindingContext parentContext, String debugName, @Nullable Object resolutionSubjectForMessage) {
079 this(parentContext, AnalyzingUtils.formDebugNameForBindingTrace(debugName, resolutionSubjectForMessage));
080 }
081
082 @Override
083 @NotNull
084 public BindingContext getBindingContext() {
085 return bindingContext;
086 }
087
088 @Override
089 public <K, V> void record(WritableSlice<K, V> slice, K key, V value) {
090 map.put(slice, key, value);
091 }
092
093 @Override
094 public <K> void record(WritableSlice<K, Boolean> slice, K key) {
095 record(slice, key, true);
096 }
097
098 @Override
099 public <K, V> V get(ReadOnlySlice<K, V> slice, K key) {
100 V value = map.get(slice, key);
101 if (slice instanceof Slices.SetSlice) {
102 assert value != null;
103 if (value.equals(true)) return value;
104 }
105 else if (value != null) {
106 return value;
107 }
108
109 return parentContext.get(slice, key);
110 }
111
112 @NotNull
113 @Override
114 public <K, V> Collection<K> getKeys(WritableSlice<K, V> slice) {
115 Collection<K> keys = map.getKeys(slice);
116 Collection<K> fromParent = parentContext.getKeys(slice);
117 if (keys.isEmpty()) return fromParent;
118 if (fromParent.isEmpty()) return keys;
119
120 List<K> result = Lists.newArrayList(keys);
121 result.addAll(fromParent);
122 return result;
123 }
124
125 public void addAllMyDataTo(@NotNull BindingTrace trace) {
126 addAllMyDataTo(trace, null, true);
127 }
128
129 public void moveAllMyDataTo(@NotNull BindingTrace trace) {
130 addAllMyDataTo(trace, null, true);
131 clear();
132 }
133
134 public void addAllMyDataTo(@NotNull BindingTrace trace, @Nullable TraceEntryFilter filter, boolean commitDiagnostics) {
135 for (Map.Entry<SlicedMapKey<?, ?>, ?> entry : map) {
136 SlicedMapKey slicedMapKey = entry.getKey();
137
138 WritableSlice slice = slicedMapKey.getSlice();
139 Object key = slicedMapKey.getKey();
140 Object value = entry.getValue();
141
142 if (filter == null || filter.accept(slice, key)) {
143 //noinspection unchecked
144 trace.record(slice, key, value);
145 }
146 }
147
148 if (!commitDiagnostics) return;
149
150 for (Diagnostic diagnostic : diagnostics) {
151 if (filter == null || filter.accept(null, diagnostic.getPsiElement())) {
152 trace.report(diagnostic);
153 }
154 }
155 }
156
157 public void clear() {
158 map.clear();
159 diagnostics.clear();
160 }
161
162 @Override
163 public void report(@NotNull Diagnostic diagnostic) {
164 diagnostics.add(diagnostic);
165 }
166
167 @Override
168 public String toString() {
169 return name;
170 }
171 }