001    /*
002     * Copyright 2010-2016 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.calls.context;
018    
019    import org.jetbrains.annotations.NotNull;
020    import org.jetbrains.annotations.Nullable;
021    import org.jetbrains.kotlin.resolve.BindingTrace;
022    import org.jetbrains.kotlin.resolve.StatementFilter;
023    import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
024    import org.jetbrains.kotlin.resolve.scopes.LexicalScope;
025    import org.jetbrains.kotlin.types.KotlinType;
026    import org.jetbrains.kotlin.types.TypeUtils;
027    
028    /**
029     * This class together with its descendants is intended to transfer data flow analysis information
030     * in top-down direction, from AST parents to children.
031     *
032     * NB: all descendants must be immutable!
033     */
034    public abstract class ResolutionContext<Context extends ResolutionContext<Context>> {
035        @NotNull
036        public final BindingTrace trace;
037        @NotNull
038        public final LexicalScope scope;
039        @NotNull
040        public final KotlinType expectedType;
041        @NotNull
042        public final DataFlowInfo dataFlowInfo;
043        @NotNull
044        public final ContextDependency contextDependency;
045        @NotNull
046        public final ResolutionResultsCache resolutionResultsCache;
047        @NotNull
048        public final StatementFilter statementFilter;
049    
050        public final boolean isAnnotationContext;
051    
052        public final boolean isDebuggerContext;
053    
054        public final boolean collectAllCandidates;
055    
056        @NotNull
057        public final CallPosition callPosition;
058    
059        protected ResolutionContext(
060                @NotNull BindingTrace trace,
061                @NotNull LexicalScope scope,
062                @NotNull KotlinType expectedType,
063                @NotNull DataFlowInfo dataFlowInfo,
064                @NotNull ContextDependency contextDependency,
065                @NotNull ResolutionResultsCache resolutionResultsCache,
066                @NotNull StatementFilter statementFilter,
067                boolean isAnnotationContext,
068                boolean isDebuggerContext,
069                boolean collectAllCandidates,
070                @NotNull CallPosition callPosition
071        ) {
072            this.trace = trace;
073            this.scope = scope;
074            this.expectedType = expectedType;
075            this.dataFlowInfo = dataFlowInfo;
076            this.contextDependency = contextDependency;
077            this.resolutionResultsCache = resolutionResultsCache;
078            this.statementFilter = statementFilter;
079            this.isAnnotationContext = isAnnotationContext;
080            this.isDebuggerContext = isDebuggerContext;
081            this.collectAllCandidates = collectAllCandidates;
082            this.callPosition = callPosition;
083        }
084    
085        protected abstract Context create(
086                @NotNull BindingTrace trace,
087                @NotNull LexicalScope scope,
088                @NotNull DataFlowInfo dataFlowInfo,
089                @NotNull KotlinType expectedType,
090                @NotNull ContextDependency contextDependency,
091                @NotNull ResolutionResultsCache resolutionResultsCache,
092                @NotNull StatementFilter statementFilter,
093                boolean collectAllCandidates,
094                @NotNull CallPosition callPosition
095        );
096    
097        @NotNull
098        private Context self() {
099            //noinspection unchecked
100            return (Context) this;
101        }
102    
103        @NotNull
104        public Context replaceBindingTrace(@NotNull BindingTrace trace) {
105            if (this.trace == trace) return self();
106            return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
107                          collectAllCandidates, callPosition);
108        }
109    
110        @NotNull
111        public Context replaceDataFlowInfo(@NotNull DataFlowInfo newDataFlowInfo) {
112            if (newDataFlowInfo == dataFlowInfo) return self();
113            return create(trace, scope, newDataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
114                          collectAllCandidates, callPosition);
115        }
116    
117        @NotNull
118        public Context replaceExpectedType(@Nullable KotlinType newExpectedType) {
119            if (newExpectedType == null) return replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE);
120            if (expectedType == newExpectedType) return self();
121            return create(trace, scope, dataFlowInfo, newExpectedType, contextDependency, resolutionResultsCache, statementFilter,
122                          collectAllCandidates, callPosition);
123        }
124    
125        @NotNull
126        public Context replaceScope(@NotNull LexicalScope newScope) {
127            if (newScope == scope) return self();
128            return create(trace, newScope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
129                          collectAllCandidates, callPosition);
130        }
131    
132        @NotNull
133        public Context replaceContextDependency(@NotNull ContextDependency newContextDependency) {
134            if (newContextDependency == contextDependency) return self();
135            return create(trace, scope, dataFlowInfo, expectedType, newContextDependency, resolutionResultsCache, statementFilter,
136                          collectAllCandidates, callPosition);
137        }
138    
139        @NotNull
140        public Context replaceResolutionResultsCache(@NotNull ResolutionResultsCache newResolutionResultsCache) {
141            if (newResolutionResultsCache == resolutionResultsCache) return self();
142            return create(trace, scope, dataFlowInfo, expectedType, contextDependency, newResolutionResultsCache, statementFilter,
143                          collectAllCandidates, callPosition);
144        }
145    
146        @NotNull
147        public Context replaceTraceAndCache(@NotNull TemporaryTraceAndCache traceAndCache) {
148            return replaceBindingTrace(traceAndCache.trace).replaceResolutionResultsCache(traceAndCache.cache);
149        }
150    
151        @NotNull
152        public Context replaceCollectAllCandidates(boolean newCollectAllCandidates) {
153            return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
154                          newCollectAllCandidates, callPosition);
155        }
156    
157        @NotNull
158        public Context replaceStatementFilter(@NotNull StatementFilter statementFilter) {
159            return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
160                          collectAllCandidates, callPosition);
161        }
162    
163        @NotNull
164        public Context replaceCallPosition(@NotNull CallPosition callPosition) {
165            return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
166                          collectAllCandidates, callPosition);
167        }
168    }