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