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 }