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.calls.context;
018    
019    import com.google.common.collect.Lists;
020    import org.jetbrains.annotations.NotNull;
021    import org.jetbrains.annotations.Nullable;
022    import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
023    import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
024    import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
025    import org.jetbrains.jet.lang.psi.CallKey;
026    import org.jetbrains.jet.lang.psi.JetExpression;
027    import org.jetbrains.jet.lang.resolve.BindingContext;
028    import org.jetbrains.jet.lang.resolve.DelegatingBindingTrace;
029    import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallWithTrace;
030    import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsImpl;
031    import org.jetbrains.jet.util.slicedmap.BasicWritableSlice;
032    import org.jetbrains.jet.util.slicedmap.Slices;
033    import org.jetbrains.jet.util.slicedmap.WritableSlice;
034    
035    import static org.jetbrains.jet.lang.psi.Call.CallType;
036    import static org.jetbrains.jet.lang.psi.Call.CallType.*;
037    
038    public class ResolutionResultsCacheImpl implements ResolutionResultsCache {
039        public static final WritableSlice<CallKey, OverloadResolutionResultsImpl<FunctionDescriptor>> RESOLUTION_RESULTS_FOR_FUNCTION = Slices.createSimpleSlice();
040        public static final WritableSlice<CallKey, OverloadResolutionResultsImpl<VariableDescriptor>> RESOLUTION_RESULTS_FOR_PROPERTY = Slices.createSimpleSlice();
041        public static final WritableSlice<CallKey, DelegatingBindingTrace> TRACE_DELTAS_CACHE = Slices.createSimpleSlice();
042        public static final WritableSlice<CallKey, CallCandidateResolutionContext<?>> DEFERRED_COMPUTATION_FOR_CALL = Slices.createSimpleSlice();
043        public static final WritableSlice<CallKey, ResolvedCallWithTrace<?>> RESOLVED_CALL_FOR_ARGUMENT = Slices.createSimpleSlice();
044    
045        static {
046            BasicWritableSlice.initSliceDebugNames(ResolutionResultsCacheImpl.class);
047        }
048    
049        private final DelegatingBindingTrace trace = new DelegatingBindingTrace(
050                BindingContext.EMPTY, "Internal binding context in resolution results cache");
051    
052        @NotNull
053        private static <D extends CallableDescriptor> WritableSlice<CallKey, OverloadResolutionResultsImpl<D>> getSliceByMemberType(@NotNull MemberType<D> memberType) {
054            //noinspection unchecked
055            return (WritableSlice<CallKey, OverloadResolutionResultsImpl<D>>)
056                    (memberType == FUNCTION_MEMBER_TYPE ? RESOLUTION_RESULTS_FOR_FUNCTION : RESOLUTION_RESULTS_FOR_PROPERTY);
057        }
058    
059        @Override
060        public <D extends CallableDescriptor> void recordResolutionResults(@NotNull CallKey callKey, @NotNull MemberType<D> memberType, @NotNull OverloadResolutionResultsImpl<D> results) {
061            trace.record(getSliceByMemberType(memberType), callKey, results);
062        }
063    
064        @Override
065        @Nullable
066        public <D extends CallableDescriptor> OverloadResolutionResultsImpl<D> getResolutionResults(@NotNull CallKey callKey, @NotNull MemberType<D> memberType) {
067            return trace.get(getSliceByMemberType(memberType), callKey);
068        }
069    
070        @Override
071        public void recordResolutionTrace(@NotNull CallKey callKey, @NotNull DelegatingBindingTrace delegatingTrace) {
072            trace.record(TRACE_DELTAS_CACHE, callKey, delegatingTrace);
073        }
074    
075        @Override
076        @Nullable
077        public DelegatingBindingTrace getResolutionTrace(@NotNull CallKey callKey) {
078            return trace.get(TRACE_DELTAS_CACHE, callKey);
079        }
080    
081        @Override
082        public <D extends CallableDescriptor> void recordDeferredComputationForCall(
083                @NotNull CallKey callKey,
084                @NotNull ResolvedCallWithTrace<D> resolvedCall,
085                @NotNull CallCandidateResolutionContext<D> deferredComputation
086        ) {
087            trace.record(DEFERRED_COMPUTATION_FOR_CALL, callKey, deferredComputation);
088            trace.record(RESOLVED_CALL_FOR_ARGUMENT, callKey, resolvedCall);
089        }
090    
091        @Override
092        @Nullable
093        public CallCandidateResolutionContext<?> getDeferredComputation(@Nullable JetExpression expression) {
094            return getValueTryingAllCallTypes(expression, DEFERRED_COMPUTATION_FOR_CALL);
095        }
096    
097        @Nullable
098        private <T> T getValueTryingAllCallTypes(
099                @Nullable JetExpression expression,
100                @NotNull WritableSlice<CallKey, T> slice
101        ) {
102            if (expression == null) return null;
103            for (CallType callType : Lists.newArrayList(DEFAULT, ARRAY_GET_METHOD, ARRAY_SET_METHOD, INVOKE)) {
104                CallKey callKey = CallKey.create(callType, expression);
105                T context = trace.get(slice, callKey);
106                if (context != null) {
107                    return context;
108                }
109            }
110            return null;
111        }
112    
113        @Nullable
114        @Override
115        public ResolvedCallWithTrace<?> getCallForArgument(@Nullable JetExpression expression) {
116            return getValueTryingAllCallTypes(expression, RESOLVED_CALL_FOR_ARGUMENT);
117        }
118    
119        @NotNull
120        public static ResolutionResultsCache create() {
121            return new ResolutionResultsCacheImpl();
122        }
123    
124        /*package*/ void addData(@NotNull ResolutionResultsCacheImpl cache) {
125            cache.trace.addAllMyDataTo(this.trace);
126        }
127    }