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