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