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.js.translate.context;
018    
019    import com.intellij.psi.PsiElement;
020    import org.jetbrains.annotations.NotNull;
021    import org.jetbrains.annotations.Nullable;
022    import org.jetbrains.kotlin.descriptors.*;
023    import org.jetbrains.kotlin.descriptors.annotations.Annotations;
024    import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor;
025    import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor;
026    import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor;
027    import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
028    import org.jetbrains.kotlin.js.backend.ast.*;
029    import org.jetbrains.kotlin.js.backend.ast.metadata.MetadataProperties;
030    import org.jetbrains.kotlin.js.config.JsConfig;
031    import org.jetbrains.kotlin.js.translate.intrinsic.Intrinsics;
032    import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator;
033    import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
034    import org.jetbrains.kotlin.js.translate.utils.TranslationUtils;
035    import org.jetbrains.kotlin.name.Name;
036    import org.jetbrains.kotlin.psi.KtExpression;
037    import org.jetbrains.kotlin.resolve.BindingContext;
038    import org.jetbrains.kotlin.resolve.BindingTrace;
039    import org.jetbrains.kotlin.resolve.DescriptorUtils;
040    import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
041    import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver;
042    
043    import java.util.*;
044    
045    import static org.jetbrains.kotlin.js.descriptorUtils.DescriptorUtilsKt.isCoroutineLambda;
046    import static org.jetbrains.kotlin.js.translate.context.UsageTrackerKt.getNameForCapturedDescriptor;
047    import static org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.isLibraryObject;
048    import static org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.isNativeObject;
049    import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.getDescriptorForElement;
050    
051    /**
052     * All the info about the state of the translation process.
053     */
054    public class TranslationContext {
055        @NotNull
056        private final DynamicContext dynamicContext;
057        @NotNull
058        private final StaticContext staticContext;
059        @NotNull
060        private final AliasingContext aliasingContext;
061        @Nullable
062        private final UsageTracker usageTracker;
063        @Nullable
064        private final TranslationContext parent;
065        @Nullable
066        private final DeclarationDescriptor declarationDescriptor;
067        @Nullable
068        private final ClassDescriptor classDescriptor;
069        @Nullable
070        private final VariableDescriptor continuationParameterDescriptor;
071    
072        @NotNull
073        public static TranslationContext rootContext(@NotNull StaticContext staticContext, @NotNull JsFunction rootFunction) {
074            JsBlock block = new JsBlock(staticContext.getTopLevelStatements());
075            DynamicContext rootDynamicContext = DynamicContext.rootContext(rootFunction.getScope(), block);
076            AliasingContext rootAliasingContext = AliasingContext.getCleanContext();
077            return new TranslationContext(null, staticContext, rootDynamicContext, rootAliasingContext, null, null);
078        }
079    
080        private final Map<JsExpression, TemporaryConstVariable> expressionToTempConstVariableCache = new HashMap<JsExpression, TemporaryConstVariable>();
081    
082        private TranslationContext(
083                @Nullable TranslationContext parent,
084                @NotNull StaticContext staticContext,
085                @NotNull DynamicContext dynamicContext,
086                @NotNull AliasingContext aliasingContext,
087                @Nullable UsageTracker usageTracker,
088                @Nullable DeclarationDescriptor declarationDescriptor
089        ) {
090            this.parent = parent;
091            this.dynamicContext = dynamicContext;
092            this.staticContext = staticContext;
093            this.aliasingContext = aliasingContext;
094            this.usageTracker = usageTracker;
095            this.declarationDescriptor = declarationDescriptor;
096            if (declarationDescriptor instanceof ClassDescriptor) {
097                this.classDescriptor = (ClassDescriptor) declarationDescriptor;
098            }
099            else {
100                this.classDescriptor = parent != null ? parent.classDescriptor : null;
101            }
102    
103            continuationParameterDescriptor = calculateContinuationParameter();
104        }
105    
106        private VariableDescriptor calculateContinuationParameter() {
107            if (parent != null && parent.declarationDescriptor == declarationDescriptor) {
108                return parent.continuationParameterDescriptor;
109            }
110            if (declarationDescriptor instanceof FunctionDescriptor) {
111                FunctionDescriptor function = (FunctionDescriptor) declarationDescriptor;
112                if (function.isSuspend() && !(function instanceof AnonymousFunctionDescriptor)) {
113                    ClassDescriptor continuationDescriptor =
114                            DescriptorUtilKt.findContinuationClassDescriptor(getCurrentModule(), NoLookupLocation.FROM_BACKEND);
115    
116                    return new LocalVariableDescriptor(
117                            declarationDescriptor,
118                            Annotations.Companion.getEMPTY(),
119                            Name.identifier("continuation"),
120                            continuationDescriptor.getDefaultType(),
121                            /* mutable = */ false,
122                            /* delegated = */ false,
123                            SourceElement.NO_SOURCE);
124                }
125            }
126            return null;
127        }
128    
129        @NotNull
130        public Collection<StaticContext.ImportedModule> getImportedModules() {
131            return staticContext.getImportedModules();
132        }
133    
134        @Nullable
135        public UsageTracker usageTracker() {
136            return usageTracker;
137        }
138    
139        @NotNull
140        public DynamicContext dynamicContext() {
141            return dynamicContext;
142        }
143    
144        @NotNull
145        public TranslationContext contextWithScope(@NotNull JsFunction fun) {
146            return this.newFunctionBody(fun, aliasingContext, declarationDescriptor);
147        }
148    
149        @NotNull
150        private TranslationContext newFunctionBody(
151                @NotNull JsFunction fun, @Nullable AliasingContext aliasingContext,
152                DeclarationDescriptor descriptor
153        ) {
154            DynamicContext dynamicContext = DynamicContext.newContext(fun.getScope(), fun.getBody());
155            if (aliasingContext == null) {
156                aliasingContext = this.aliasingContext.inner();
157            }
158    
159            return new TranslationContext(this, this.staticContext, dynamicContext, aliasingContext, this.usageTracker, descriptor);
160        }
161    
162        @NotNull
163        public TranslationContext newFunctionBodyWithUsageTracker(@NotNull JsFunction fun, @NotNull MemberDescriptor descriptor) {
164            DynamicContext dynamicContext = DynamicContext.newContext(fun.getScope(), fun.getBody());
165            UsageTracker usageTracker = new UsageTracker(this.usageTracker, descriptor, fun.getScope());
166            return new TranslationContext(this, this.staticContext, dynamicContext, this.aliasingContext.inner(), usageTracker, descriptor);
167        }
168    
169        @NotNull
170        public TranslationContext innerWithUsageTracker(@NotNull JsScope scope, @NotNull MemberDescriptor descriptor) {
171            UsageTracker usageTracker = new UsageTracker(this.usageTracker, descriptor, scope);
172            return new TranslationContext(this, staticContext, dynamicContext, aliasingContext.inner(), usageTracker, descriptor);
173        }
174    
175        @NotNull
176        public TranslationContext inner(@NotNull MemberDescriptor descriptor) {
177            return new TranslationContext(this, staticContext, dynamicContext, aliasingContext.inner(), usageTracker, descriptor);
178        }
179    
180        @NotNull
181        public TranslationContext innerBlock(@NotNull JsBlock block) {
182            return new TranslationContext(this, staticContext, dynamicContext.innerBlock(block), aliasingContext, usageTracker,
183                                          this.declarationDescriptor);
184        }
185    
186        @NotNull
187        public TranslationContext innerBlock() {
188            return innerBlock(new JsBlock());
189        }
190    
191        @NotNull
192        public TranslationContext newDeclaration(@NotNull DeclarationDescriptor descriptor) {
193            JsBlock innerBlock = getBlockForDescriptor(descriptor);
194            if (innerBlock == null) {
195                innerBlock = dynamicContext.jsBlock();
196            }
197            DynamicContext dynamicContext = DynamicContext.newContext(getScopeForDescriptor(descriptor), innerBlock);
198            return new TranslationContext(this, staticContext, dynamicContext, aliasingContext, usageTracker, descriptor);
199        }
200    
201        @NotNull
202        private TranslationContext innerWithAliasingContext(AliasingContext aliasingContext) {
203            return new TranslationContext(this, staticContext, dynamicContext, aliasingContext, usageTracker, declarationDescriptor);
204        }
205    
206        @NotNull
207        public TranslationContext innerContextWithAliased(@NotNull DeclarationDescriptor correspondingDescriptor, @NotNull JsExpression alias) {
208            return this.innerWithAliasingContext(aliasingContext.inner(correspondingDescriptor, alias));
209        }
210    
211        @NotNull
212        public TranslationContext innerContextWithAliasesForExpressions(@NotNull Map<KtExpression, JsExpression> aliases) {
213            if (aliases.isEmpty()) return this;
214            return this.innerWithAliasingContext(aliasingContext.withExpressionsAliased(aliases));
215        }
216    
217        @NotNull
218        public TranslationContext innerContextWithDescriptorsAliased(@NotNull Map<DeclarationDescriptor, JsExpression> aliases) {
219            if (aliases.isEmpty()) return this;
220            return this.innerWithAliasingContext(aliasingContext.withDescriptorsAliased(aliases));
221        }
222    
223        @Nullable
224        private JsBlock getBlockForDescriptor(@NotNull DeclarationDescriptor descriptor) {
225            if (descriptor instanceof CallableDescriptor) {
226                return getFunctionObject((CallableDescriptor) descriptor).getBody();
227            }
228            else {
229                return null;
230            }
231        }
232    
233        @Nullable
234        public ClassDescriptor getClassDescriptor() {
235            return classDescriptor;
236        }
237    
238        @NotNull
239        public BindingContext bindingContext() {
240            return staticContext.getBindingContext();
241        }
242    
243        @NotNull
244        public BindingTrace bindingTrace() {
245            return staticContext.getBindingTrace();
246        }
247    
248        @NotNull
249        public JsScope getScopeForDescriptor(@NotNull DeclarationDescriptor descriptor) {
250            return staticContext.getScopeForDescriptor(descriptor);
251        }
252    
253        @NotNull
254        public JsName getNameForElement(@NotNull PsiElement element) {
255            DeclarationDescriptor descriptor = getDescriptorForElement(bindingContext(), element);
256            return getNameForDescriptor(descriptor);
257        }
258    
259        @NotNull
260        public JsName getNameForDescriptor(@NotNull DeclarationDescriptor descriptor) {
261            return staticContext.getNameForDescriptor(descriptor);
262        }
263    
264        @NotNull
265        public JsName getInnerNameForDescriptor(@NotNull DeclarationDescriptor descriptor) {
266            return staticContext.getInnerNameForDescriptor(descriptor);
267        }
268    
269        @NotNull
270        public JsName getNameForObjectInstance(@NotNull ClassDescriptor descriptor) {
271            return staticContext.getNameForObjectInstance(descriptor);
272        }
273    
274        @NotNull
275        public JsNameRef getQualifiedReference(@NotNull DeclarationDescriptor descriptor) {
276            if (descriptor instanceof MemberDescriptor && isFromCurrentModule(descriptor) && isPublicInlineFunction()) {
277                staticContext.export((MemberDescriptor) descriptor, true);
278            }
279            return staticContext.getQualifiedReference(descriptor);
280        }
281    
282        @NotNull
283        public JsNameRef getInnerReference(@NotNull DeclarationDescriptor descriptor) {
284            if (isNativeObject(descriptor) || isLibraryObject(descriptor)) {
285                return getQualifiedReference(descriptor);
286            }
287    
288            return JsAstUtils.pureFqn(getInnerNameForDescriptor(descriptor), null);
289        }
290    
291        @NotNull
292        public JsName getNameForBackingField(@NotNull PropertyDescriptor property) {
293            return staticContext.getNameForBackingField(property);
294        }
295    
296        @NotNull
297        public TemporaryVariable declareTemporary(@Nullable JsExpression initExpression) {
298            return dynamicContext.declareTemporary(initExpression);
299        }
300    
301        @NotNull
302        public JsExpression defineTemporary(@NotNull JsExpression initExpression) {
303            TemporaryVariable var = dynamicContext.declareTemporary(initExpression);
304            addStatementToCurrentBlock(var.assignmentStatement());
305            return var.reference();
306        }
307    
308        @NotNull
309        public JsExpression cacheExpressionIfNeeded(@NotNull JsExpression expression) {
310            return TranslationUtils.isCacheNeeded(expression) ? defineTemporary(expression) : expression;
311        }
312    
313        @NotNull
314        public TemporaryConstVariable getOrDeclareTemporaryConstVariable(@NotNull JsExpression expression) {
315            TemporaryConstVariable tempVar = expressionToTempConstVariableCache.get(expression);
316    
317            if (tempVar == null) {
318                TemporaryVariable tmpVar = declareTemporary(expression);
319    
320                tempVar = new TemporaryConstVariable(tmpVar.name(), tmpVar.assignmentExpression());
321    
322                expressionToTempConstVariableCache.put(expression, tempVar);
323                expressionToTempConstVariableCache.put(tmpVar.assignmentExpression(), tempVar);
324            }
325    
326            return tempVar;
327        }
328    
329        public void associateExpressionToLazyValue(JsExpression expression, TemporaryConstVariable temporaryConstVariable) {
330            assert expression == temporaryConstVariable.assignmentExpression();
331            expressionToTempConstVariableCache.put(expression, temporaryConstVariable);
332        }
333    
334        @NotNull
335        public Namer namer() {
336            return staticContext.getNamer();
337        }
338    
339        @NotNull
340        public Intrinsics intrinsics() {
341            return staticContext.getIntrinsics();
342        }
343    
344        @NotNull
345        public JsProgram program() {
346            return staticContext.getProgram();
347        }
348    
349        @NotNull
350        public JsConfig getConfig() {
351            return staticContext.getConfig();
352        }
353    
354        @NotNull
355        public JsScope scope() {
356            return dynamicContext.getScope();
357        }
358    
359        @NotNull
360        public AliasingContext aliasingContext() {
361            return aliasingContext;
362        }
363    
364        @NotNull
365        public JsFunction getFunctionObject(@NotNull CallableDescriptor descriptor) {
366            return staticContext.getFunctionWithScope(descriptor);
367        }
368    
369        public void addStatementToCurrentBlock(@NotNull JsStatement statement) {
370            dynamicContext.jsBlock().getStatements().add(statement);
371        }
372    
373        public void addStatementsToCurrentBlock(@NotNull Collection<JsStatement> statements) {
374            dynamicContext.jsBlock().getStatements().addAll(statements);
375        }
376    
377        public void addStatementsToCurrentBlockFrom(@NotNull TranslationContext context) {
378            addStatementsToCurrentBlockFrom(context.dynamicContext().jsBlock());
379        }
380    
381        public void addStatementsToCurrentBlockFrom(@NotNull JsBlock block) {
382            dynamicContext.jsBlock().getStatements().addAll(block.getStatements());
383        }
384    
385        public boolean currentBlockIsEmpty() {
386            return dynamicContext.jsBlock().isEmpty();
387        }
388    
389        public void moveVarsFrom(@NotNull TranslationContext context) {
390            dynamicContext.moveVarsFrom(context.dynamicContext());
391        }
392    
393        @NotNull
394        public JsBlock getCurrentBlock() {
395            return dynamicContext.jsBlock();
396        }
397    
398        @Nullable
399        public JsExpression getAliasForDescriptor(@NotNull DeclarationDescriptor descriptor) {
400            JsExpression nameRef = captureIfNeedAndGetCapturedName(descriptor);
401            if (nameRef != null) {
402                return nameRef;
403            }
404    
405            return aliasingContext.getAliasForDescriptor(descriptor);
406        }
407    
408        @NotNull
409        public JsExpression getDispatchReceiver(@NotNull ReceiverParameterDescriptor descriptor) {
410            JsExpression alias = getAliasForDescriptor(descriptor);
411            if (alias != null) {
412                return alias;
413            }
414            if (isCoroutineLambda(descriptor.getContainingDeclaration())) {
415                JsNameRef result = new JsNameRef("$$controller$$", JsAstUtils.stateMachineReceiver());
416                MetadataProperties.setCoroutineController(result, true);
417                return result;
418            }
419    
420            if (DescriptorUtils.isObject(descriptor.getContainingDeclaration())) {
421                if (isConstructorOrDirectScope(descriptor.getContainingDeclaration())) {
422                    return JsLiteral.THIS;
423                }
424                else {
425                    ClassDescriptor objectDescriptor = (ClassDescriptor) descriptor.getContainingDeclaration();
426                    return ReferenceTranslator.translateAsValueReference(objectDescriptor, this);
427                }
428            }
429    
430            if (descriptor.getValue() instanceof ExtensionReceiver) return JsLiteral.THIS;
431    
432            ClassifierDescriptor classifier = descriptor.getValue().getType().getConstructor().getDeclarationDescriptor();
433    
434            // TODO: can't tell why this assertion is valid, revisit this code later
435            assert classifier instanceof ClassDescriptor;
436    
437            ClassDescriptor cls = (ClassDescriptor) classifier;
438    
439            assert classDescriptor != null : "Can't get ReceiverParameterDescriptor in top level";
440            JsExpression receiver = getAliasForDescriptor(classDescriptor.getThisAsReceiverParameter());
441            if (receiver == null) {
442                receiver = JsLiteral.THIS;
443            }
444    
445            return getDispatchReceiverPath(cls, receiver);
446        }
447    
448        private boolean isConstructorOrDirectScope(DeclarationDescriptor descriptor) {
449            return descriptor == DescriptorUtils.getParentOfType(declarationDescriptor, ClassDescriptor.class, false);
450        }
451    
452        @NotNull
453        private JsExpression getDispatchReceiverPath(@Nullable ClassDescriptor cls, JsExpression thisExpression) {
454            if (cls != null) {
455                JsExpression alias = getAliasForDescriptor(cls);
456                if (alias != null) {
457                    return alias;
458                }
459            }
460    
461            if (classDescriptor == cls || parent == null) {
462                return thisExpression;
463            }
464    
465            if (classDescriptor != parent.classDescriptor) {
466                return new JsNameRef(Namer.OUTER_FIELD_NAME, parent.getDispatchReceiverPath(cls, thisExpression));
467            }
468            else {
469                return parent.getDispatchReceiverPath(cls, thisExpression);
470            }
471        }
472    
473        @Nullable
474        private JsExpression captureIfNeedAndGetCapturedName(DeclarationDescriptor descriptor) {
475            if (usageTracker != null) {
476                usageTracker.used(descriptor);
477    
478                JsName name = getNameForCapturedDescriptor(usageTracker, descriptor);
479                if (name != null) {
480                    JsExpression result;
481                    if (shouldCaptureViaThis()) {
482                        result = JsLiteral.THIS;
483                        int depth = getOuterLocalClassDepth();
484                        for (int i = 0; i < depth; ++i) {
485                            result = new JsNameRef(Namer.OUTER_FIELD_NAME, result);
486                        }
487                        result = new JsNameRef(name, result);
488                    }
489                    else {
490                        result = name.makeRef();
491                    }
492                    return result;
493                }
494            }
495    
496            return null;
497        }
498    
499        private int getOuterLocalClassDepth() {
500            if (usageTracker == null) return 0;
501            MemberDescriptor capturingDescriptor = usageTracker.getContainingDescriptor();
502            if (!(capturingDescriptor instanceof ClassDescriptor)) return 0;
503    
504            ClassDescriptor capturingClassDescriptor = (ClassDescriptor) capturingDescriptor;
505            ClassDescriptor currentDescriptor = classDescriptor;
506            if (currentDescriptor == null) return 0;
507    
508            int depth = 0;
509            while (currentDescriptor != capturingClassDescriptor) {
510                DeclarationDescriptor container = currentDescriptor.getContainingDeclaration();
511                if (!(container instanceof ClassDescriptor)) return 0;
512                currentDescriptor = (ClassDescriptor) container;
513                depth++;
514            }
515            return depth;
516        }
517    
518        private boolean shouldCaptureViaThis() {
519            if (declarationDescriptor == null) return false;
520    
521            if (DescriptorUtils.isDescriptorWithLocalVisibility(declarationDescriptor)) return false;
522            if (declarationDescriptor instanceof ConstructorDescriptor &&
523                DescriptorUtils.isDescriptorWithLocalVisibility(declarationDescriptor.getContainingDeclaration())) return false;
524    
525            return true;
526        }
527    
528        @Nullable
529        public DeclarationDescriptor getDeclarationDescriptor() {
530            return declarationDescriptor;
531        }
532    
533        public void putClassOrConstructorClosure(@NotNull MemberDescriptor descriptor, @NotNull List<DeclarationDescriptor> closure) {
534            staticContext.putClassOrConstructorClosure(descriptor, closure);
535        }
536    
537        @Nullable
538        public List<DeclarationDescriptor> getClassOrConstructorClosure(@NotNull MemberDescriptor classOrConstructor) {
539            if (classOrConstructor instanceof TypeAliasConstructorDescriptor) {
540                ClassConstructorDescriptor constructorDescriptor = ((TypeAliasConstructorDescriptor) classOrConstructor).getUnderlyingConstructorDescriptor();
541                return getClassOrConstructorClosure(constructorDescriptor);
542            }
543    
544            List<DeclarationDescriptor> result = staticContext.getClassOrConstructorClosure(classOrConstructor);
545            if (result == null &&
546                classOrConstructor instanceof ConstructorDescriptor &&
547                ((ConstructorDescriptor) classOrConstructor).isPrimary()
548            ) {
549                result = staticContext.getClassOrConstructorClosure((ClassDescriptor) classOrConstructor.getContainingDeclaration());
550            }
551            return result;
552        }
553    
554        /**
555         * Gets an expression to pass to a constructor of a closure function. I.e. consider the case:
556         *
557         * ```
558         * fun a(x) {
559         *     fun b(y) = x + y
560         *     return b
561         * }
562         * ```
563         *
564         * Here, `x` is a free variable of `b`. Transform `a` into the following form:
565         *
566         * ```
567         * fun a(x) {
568         *     fun b0(x0) = { y -> x0 * y }
569         *     return b0(x)
570         * }
571         * ```
572         *
573         * This function generates arguments passed to newly generated `b0` closure, as well as for the similar case of local class and
574         * object expression.
575         *
576         * @param descriptor represents a free variable or, more generally, free declaration.
577         * @return expression to pass to a closure constructor.
578         */
579        @NotNull
580        public JsExpression getArgumentForClosureConstructor(@NotNull DeclarationDescriptor descriptor) {
581            JsExpression alias = getAliasForDescriptor(descriptor);
582            if (alias != null) return alias;
583            if (descriptor instanceof ReceiverParameterDescriptor) {
584                return getDispatchReceiver((ReceiverParameterDescriptor) descriptor);
585            }
586            if (isCoroutineLambda(descriptor)) {
587                return JsLiteral.THIS;
588            }
589            return getNameForDescriptor(descriptor).makeRef();
590        }
591    
592        @Nullable
593        public JsName getOuterClassReference(ClassDescriptor descriptor) {
594            DeclarationDescriptor container = descriptor.getContainingDeclaration();
595            if (!(container instanceof ClassDescriptor) || !descriptor.isInner()) {
596                return null;
597            }
598    
599            return staticContext.getScopeForDescriptor(descriptor).declareName(Namer.OUTER_FIELD_NAME);
600        }
601    
602        public void startDeclaration() {
603            ClassDescriptor classDescriptor = this.classDescriptor;
604            if (classDescriptor != null && !(classDescriptor.getContainingDeclaration() instanceof ClassOrPackageFragmentDescriptor)) {
605                staticContext.getDeferredCallSites().put(classDescriptor, new ArrayList<DeferredCallSite>());
606            }
607        }
608    
609        @NotNull
610        public List<DeferredCallSite> endDeclaration() {
611            List<DeferredCallSite> result = null;
612            if (classDescriptor != null) {
613                result = staticContext.getDeferredCallSites().remove(classDescriptor);
614            }
615            if (result == null) {
616                result = Collections.emptyList();
617            }
618            return result;
619        }
620    
621        public boolean shouldBeDeferred(@NotNull ClassConstructorDescriptor constructor) {
622            ClassDescriptor classDescriptor = constructor.getContainingDeclaration();
623            return staticContext.getDeferredCallSites().containsKey(classDescriptor);
624        }
625    
626        public void deferConstructorCall(@NotNull ClassConstructorDescriptor constructor, @NotNull List<JsExpression> invocationArgs) {
627            ClassDescriptor classDescriptor = constructor.getContainingDeclaration();
628            List<DeferredCallSite> callSites = staticContext.getDeferredCallSites().get(classDescriptor);
629            if (callSites == null) throw new IllegalStateException("This method should be call only when `shouldBeDeferred` method " +
630                                                                   "reports true for given constructor: " + constructor);
631            callSites.add(new DeferredCallSite(constructor, invocationArgs, this));
632        }
633    
634        @Nullable
635        public JsExpression getModuleExpressionFor(@NotNull DeclarationDescriptor descriptor) {
636            return staticContext.getModuleExpressionFor(descriptor);
637        }
638    
639        public void addDeclarationStatement(@NotNull JsStatement statement) {
640            staticContext.getDeclarationStatements().add(statement);
641        }
642    
643        public void addTopLevelStatement(@NotNull JsStatement statement) {
644            staticContext.getTopLevelStatements().add(statement);
645        }
646    
647        @NotNull
648        public JsName createGlobalName(@NotNull String suggestedName) {
649            return staticContext.getRootFunction().getScope().declareTemporaryName(suggestedName);
650        }
651    
652        @NotNull
653        public JsFunction createRootScopedFunction(@NotNull DeclarationDescriptor descriptor) {
654            return createRootScopedFunction(descriptor.toString());
655        }
656    
657        @NotNull
658        public JsFunction createRootScopedFunction(@NotNull String description) {
659            return new JsFunction(staticContext.getRootFunction().getScope(), new JsBlock(), description);
660        }
661    
662        public void addClass(@NotNull ClassDescriptor classDescriptor) {
663            staticContext.addClass(classDescriptor);
664        }
665    
666        public void export(@NotNull MemberDescriptor descriptor) {
667            staticContext.export(descriptor, false);
668        }
669    
670        public boolean isFromCurrentModule(@NotNull DeclarationDescriptor descriptor) {
671            return staticContext.getCurrentModule() == DescriptorUtilsKt.getModule(descriptor);
672        }
673    
674        public boolean isPublicInlineFunction() {
675            DeclarationDescriptor descriptor = declarationDescriptor;
676            while (descriptor instanceof FunctionDescriptor) {
677                FunctionDescriptor function = (FunctionDescriptor) descriptor;
678                if (function.isInline() && DescriptorUtilsKt.isEffectivelyPublicApi(function)) {
679                    return true;
680                }
681                descriptor = descriptor.getContainingDeclaration();
682            }
683            return false;
684        }
685    
686        @Nullable
687        public VariableDescriptor getContinuationParameterDescriptor() {
688            return continuationParameterDescriptor;
689        }
690    
691        @NotNull
692        public ModuleDescriptor getCurrentModule() {
693            return staticContext.getCurrentModule();
694        }
695    
696        @Nullable
697        public TranslationContext getParent() {
698            return parent;
699        }
700    }