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.expression;
018    
019    import com.google.dart.compiler.backend.js.ast.*;
020    import com.google.dart.compiler.backend.js.ast.metadata.MetadataProperties;
021    import com.intellij.psi.PsiElement;
022    import com.intellij.psi.util.PsiTreeUtil;
023    import kotlin.collections.CollectionsKt;
024    import org.jetbrains.annotations.NotNull;
025    import org.jetbrains.annotations.Nullable;
026    import org.jetbrains.kotlin.descriptors.*;
027    import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
028    import org.jetbrains.kotlin.descriptors.annotations.KotlinRetention;
029    import org.jetbrains.kotlin.js.translate.context.Namer;
030    import org.jetbrains.kotlin.js.translate.context.TranslationContext;
031    import org.jetbrains.kotlin.js.translate.declaration.ClassTranslator;
032    import org.jetbrains.kotlin.js.translate.general.Translation;
033    import org.jetbrains.kotlin.js.translate.general.TranslatorVisitor;
034    import org.jetbrains.kotlin.js.translate.operation.BinaryOperationTranslator;
035    import org.jetbrains.kotlin.js.translate.operation.UnaryOperationTranslator;
036    import org.jetbrains.kotlin.js.translate.reference.*;
037    import org.jetbrains.kotlin.js.translate.utils.BindingUtils;
038    import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
039    import org.jetbrains.kotlin.js.translate.utils.UtilsKt;
040    import org.jetbrains.kotlin.psi.*;
041    import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt;
042    import org.jetbrains.kotlin.resolve.BindingContext;
043    import org.jetbrains.kotlin.resolve.BindingContextUtils;
044    import org.jetbrains.kotlin.resolve.DescriptorUtils;
045    import org.jetbrains.kotlin.resolve.bindingContextUtil.BindingContextUtilsKt;
046    import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
047    import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
048    import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
049    import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
050    import org.jetbrains.kotlin.resolve.inline.InlineUtil;
051    import org.jetbrains.kotlin.types.KotlinType;
052    
053    import java.util.ArrayList;
054    import java.util.List;
055    
056    import static org.jetbrains.kotlin.js.translate.context.Namer.GET_KCLASS;
057    import static org.jetbrains.kotlin.js.translate.context.Namer.GET_KCLASS_FROM_EXPRESSION;
058    import static org.jetbrains.kotlin.js.translate.context.Namer.getCapturedVarAccessor;
059    import static org.jetbrains.kotlin.js.translate.general.Translation.translateAsExpression;
060    import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.*;
061    import static org.jetbrains.kotlin.js.translate.utils.ErrorReportingUtils.message;
062    import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.convertToStatement;
063    import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.newVar;
064    import static org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils.getReceiverParameterForDeclaration;
065    import static org.jetbrains.kotlin.js.translate.utils.TranslationUtils.translateInitializerForProperty;
066    import static org.jetbrains.kotlin.resolve.BindingContext.DECLARATION_TO_DESCRIPTOR;
067    import static org.jetbrains.kotlin.resolve.BindingContext.LABEL_TARGET;
068    import static org.jetbrains.kotlin.resolve.BindingContextUtils.isVarCapturedInClosure;
069    import static org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt.getResolvedCallWithAssert;
070    import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isFunctionExpression;
071    import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isFunctionLiteral;
072    
073    public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
074        @Override
075        protected JsNode emptyResult(@NotNull TranslationContext context) {
076            return JsLiteral.NULL;
077        }
078    
079        @Override
080        @NotNull
081        public JsNode visitConstantExpression(@NotNull KtConstantExpression expression, @NotNull TranslationContext context) {
082            return translateConstantExpression(expression, context).source(expression);
083        }
084    
085        @NotNull
086        private static JsNode translateConstantExpression(@NotNull KtConstantExpression expression, @NotNull TranslationContext context) {
087            CompileTimeConstant<?> compileTimeValue = ConstantExpressionEvaluator.getConstant(expression, context.bindingContext());
088            assert compileTimeValue != null : message(expression, "Expression is not compile time value: " + expression.getText() + " ");
089    
090            JsNode result = Translation.translateConstant(compileTimeValue, expression, context);
091            if (result == null) {
092                throw new AssertionError(message(expression, "Unsupported constant expression: " + expression.getText() + " "));
093            }
094    
095            return result;
096        }
097    
098        @Override
099        @NotNull
100        public JsNode visitBlockExpression(@NotNull KtBlockExpression jetBlock, @NotNull TranslationContext context) {
101            List<KtExpression> statements = jetBlock.getStatements();
102            JsBlock jsBlock = new JsBlock();
103            for (KtExpression statement : statements) {
104                JsNode jsNode = Translation.translateExpression(statement, context, jsBlock);
105                JsStatement jsStatement = convertToStatement(jsNode);
106                if (!JsAstUtils.isEmptyStatement(jsStatement)) {
107                    jsBlock.getStatements().add(jsStatement);
108                }
109            }
110            return jsBlock;
111        }
112    
113        @Override
114        public JsNode visitDestructuringDeclaration(@NotNull KtDestructuringDeclaration multiDeclaration, @NotNull TranslationContext context) {
115            KtExpression jetInitializer = multiDeclaration.getInitializer();
116            assert jetInitializer != null : "Initializer for multi declaration must be not null";
117            JsExpression initializer = Translation.translateAsExpression(jetInitializer, context);
118            return DestructuringDeclarationTranslator.translate(multiDeclaration, context.scope().declareTemporary(), initializer, context);
119        }
120    
121        @Override
122        @NotNull
123        public JsNode visitReturnExpression(@NotNull KtReturnExpression jetReturnExpression, @NotNull TranslationContext context) {
124            KtExpression returned = jetReturnExpression.getReturnedExpression();
125    
126            // TODO: add related descriptor to context and use it here
127            KtDeclarationWithBody parent = PsiTreeUtil.getParentOfType(jetReturnExpression, KtDeclarationWithBody.class);
128            if (parent instanceof KtSecondaryConstructor) {
129                return new JsReturn(new JsNameRef(Namer.ANOTHER_THIS_PARAMETER_NAME)).source(jetReturnExpression);
130            }
131    
132            JsReturn jsReturn;
133            if (returned == null) {
134                jsReturn = new JsReturn(null);
135            }
136            else {
137                JsExpression jsReturnExpression = translateAsExpression(returned, context);
138    
139                jsReturn = new JsReturn(jsReturnExpression);
140            }
141    
142            MetadataProperties.setReturnTarget(jsReturn, getNonLocalReturnTarget(jetReturnExpression, context));
143    
144            return jsReturn.source(jetReturnExpression);
145        }
146    
147        @Nullable
148        private static FunctionDescriptor getNonLocalReturnTarget(
149                @NotNull KtReturnExpression expression,
150                @NotNull TranslationContext context
151        ) {
152            DeclarationDescriptor descriptor = context.getDeclarationDescriptor();
153            assert descriptor instanceof CallableMemberDescriptor : "Return expression can only be inside callable declaration: " +
154                                                                    PsiUtilsKt.getTextWithLocation(expression);
155            KtSimpleNameExpression target = expression.getTargetLabel();
156    
157            //call inside lambda
158            if (isFunctionLiteral(descriptor) || isFunctionExpression(descriptor)) {
159                if (target == null) {
160                    if (isFunctionLiteral(descriptor)) {
161                        return BindingContextUtils.getContainingFunctionSkipFunctionLiterals(descriptor, true).getFirst();
162                    }
163                }
164                else {
165                    PsiElement element = context.bindingContext().get(LABEL_TARGET, target);
166                    descriptor = context.bindingContext().get(DECLARATION_TO_DESCRIPTOR, element);
167                }
168            }
169    
170            assert descriptor == null || descriptor instanceof FunctionDescriptor :
171                    "Function descriptor expected to be target of return label: " + PsiUtilsKt.getTextWithLocation(expression);
172            return (FunctionDescriptor) descriptor;
173        }
174    
175        @Override
176        @NotNull
177        public JsNode visitParenthesizedExpression(@NotNull KtParenthesizedExpression expression,
178                @NotNull TranslationContext context) {
179            KtExpression expressionInside = expression.getExpression();
180            if (expressionInside != null) {
181                return Translation.translateExpression(expressionInside, context);
182            }
183            return JsEmpty.INSTANCE;
184        }
185    
186        @Override
187        @NotNull
188        public JsNode visitBinaryExpression(@NotNull KtBinaryExpression expression,
189                @NotNull TranslationContext context) {
190            return BinaryOperationTranslator.translate(expression, context);
191        }
192    
193        @Override
194        @NotNull
195        // assume it is a local variable declaration
196        public JsNode visitProperty(@NotNull KtProperty expression, @NotNull TranslationContext context) {
197            VariableDescriptor descriptor = BindingContextUtils.getNotNull(context.bindingContext(), BindingContext.VARIABLE, expression);
198            JsExpression initializer = translateInitializerForProperty(expression, context);
199    
200            JsName name = context.getNameForDescriptor(descriptor);
201            if (isVarCapturedInClosure(context.bindingContext(), descriptor)) {
202                JsNameRef alias = getCapturedVarAccessor(name.makeRef());
203                initializer = JsAstUtils.wrapValue(alias, initializer == null ? JsLiteral.NULL : initializer);
204            }
205    
206            return newVar(name, initializer).source(expression);
207        }
208    
209        @Override
210        @NotNull
211        public JsNode visitCallableReferenceExpression(@NotNull KtCallableReferenceExpression expression, @NotNull TranslationContext context) {
212            return CallableReferenceTranslator.INSTANCE.translate(expression, context);
213        }
214    
215        @Override
216        public JsNode visitClassLiteralExpression(
217                @NotNull KtClassLiteralExpression expression, TranslationContext context
218        ) {
219            KotlinType expressionType = context.bindingContext().getType(expression);
220            assert expressionType != null;
221    
222            ClassifierDescriptor expressionClassifier = expressionType.getConstructor().getDeclarationDescriptor();
223            assert expressionClassifier != null && DescriptorUtils.getFqName(expressionClassifier).asString().equals("kotlin.reflect.KClass")
224                    : "::class expression should be type checked to a KClass: " + expressionType;
225    
226            KotlinType type = CollectionsKt.single(expressionType.getArguments()).getType();
227            JsNameRef referenceToJsClass = UtilsKt.getReferenceToJsClass(type, context);
228    
229            ClassifierDescriptor typeClassifier = type.getConstructor().getDeclarationDescriptor();
230            if (typeClassifier != null && DescriptorUtils.isEnumEntry(typeClassifier)) {
231                return new JsInvocation(context.namer().kotlin(GET_KCLASS_FROM_EXPRESSION), referenceToJsClass);
232            }
233    
234            return new JsInvocation(context.namer().kotlin(GET_KCLASS), referenceToJsClass);
235        }
236    
237        @Override
238        @NotNull
239        public JsNode visitCallExpression(
240                @NotNull KtCallExpression expression,
241                @NotNull TranslationContext context
242        ) {
243            return CallExpressionTranslator.translate(expression, null, context).source(expression);
244        }
245    
246        @Override
247        @NotNull
248        public JsNode visitIfExpression(@NotNull KtIfExpression expression, @NotNull TranslationContext context) {
249            assert expression.getCondition() != null : "condition should not ne null: " + expression.getText();
250            JsExpression testExpression = Translation.translateAsExpression(expression.getCondition(), context);
251    
252            boolean isKotlinExpression = BindingContextUtilsKt.isUsedAsExpression(expression, context.bindingContext());
253    
254            KtExpression thenExpression = expression.getThen();
255            KtExpression elseExpression = expression.getElse();
256    
257            JsStatement thenStatement =
258                    thenExpression != null ? Translation.translateAsStatementAndMergeInBlockIfNeeded(thenExpression, context) : null;
259            JsStatement elseStatement =
260                    elseExpression != null ? Translation.translateAsStatementAndMergeInBlockIfNeeded(elseExpression, context) : null;
261    
262            if (isKotlinExpression) {
263                JsExpression jsThenExpression = JsAstUtils.extractExpressionFromStatement(thenStatement);
264                JsExpression jsElseExpression = JsAstUtils.extractExpressionFromStatement(elseStatement);
265                boolean canBeJsExpression = jsThenExpression != null && jsElseExpression != null;
266                if (canBeJsExpression) {
267                    return new JsConditional(testExpression, jsThenExpression, jsElseExpression).source(expression);
268                }
269            }
270            JsIf ifStatement = new JsIf(testExpression, thenStatement, elseStatement);
271            return ifStatement.source(expression);
272        }
273    
274        @Override
275        @NotNull
276        public JsExpression visitSimpleNameExpression(@NotNull KtSimpleNameExpression expression,
277                @NotNull TranslationContext context) {
278            return ReferenceTranslator.translateSimpleName(expression, context).source(expression);
279        }
280    
281        @Override
282        @NotNull
283        public JsNode visitWhileExpression(@NotNull KtWhileExpression expression, @NotNull TranslationContext context) {
284            return LoopTranslator.createWhile(false, expression, context);
285        }
286    
287        @Override
288        @NotNull
289        public JsNode visitDoWhileExpression(@NotNull KtDoWhileExpression expression, @NotNull TranslationContext context) {
290            return LoopTranslator.createWhile(true, expression, context);
291        }
292    
293        @Override
294        @NotNull
295        public JsNode visitStringTemplateExpression(@NotNull KtStringTemplateExpression expression, @NotNull TranslationContext context) {
296            JsStringLiteral stringLiteral = resolveAsStringConstant(expression, context);
297            if (stringLiteral != null) {
298                return stringLiteral;
299            }
300            return resolveAsTemplate(expression, context).source(expression);
301        }
302    
303        @NotNull
304        private static JsNode resolveAsTemplate(@NotNull KtStringTemplateExpression expression,
305                @NotNull TranslationContext context) {
306            return StringTemplateTranslator.translate(expression, context);
307        }
308    
309        @Nullable
310        private static JsStringLiteral resolveAsStringConstant(@NotNull KtExpression expression,
311                @NotNull TranslationContext context) {
312            Object value = getCompileTimeValue(context.bindingContext(), expression);
313            if (value == null) {
314                return null;
315            }
316            assert value instanceof String : "Compile time constant template should be a String constant.";
317            String constantString = (String) value;
318            return context.program().getStringLiteral(constantString);
319        }
320    
321        @Override
322        @NotNull
323        public JsNode visitDotQualifiedExpression(@NotNull KtDotQualifiedExpression expression, @NotNull TranslationContext context) {
324            return QualifiedExpressionTranslator.translateQualifiedExpression(expression, context);
325        }
326    
327        @Override
328        public JsNode visitLabeledExpression(@NotNull KtLabeledExpression expression, @NotNull TranslationContext context) {
329            KtExpression baseExpression = expression.getBaseExpression();
330            assert baseExpression != null;
331    
332            if (BindingContextUtilsKt.isUsedAsExpression(expression, context.bindingContext())) {
333                return Translation.translateAsExpression(baseExpression, context).source(expression);
334            }
335    
336            JsScope scope = context.scope();
337            assert scope instanceof JsFunctionScope: "Labeled statement is unexpected outside of function scope";
338            JsFunctionScope functionScope = (JsFunctionScope) scope;
339    
340            String labelIdent = getReferencedName(expression.getTargetLabel());
341    
342            JsName labelName = functionScope.enterLabel(labelIdent);
343            JsStatement baseStatement = Translation.translateAsStatement(baseExpression, context);
344            functionScope.exitLabel();
345    
346            return new JsLabel(labelName, baseStatement).source(expression);
347        }
348    
349        @Override
350        @NotNull
351        public JsNode visitPrefixExpression(
352                @NotNull KtPrefixExpression expression,
353                @NotNull TranslationContext context
354        ) {
355            return UnaryOperationTranslator.translate(expression, context).source(expression);
356        }
357    
358        @Override
359        @NotNull
360        public JsNode visitPostfixExpression(@NotNull KtPostfixExpression expression,
361                @NotNull TranslationContext context) {
362            return UnaryOperationTranslator.translate(expression, context).source(expression);
363        }
364    
365        @Override
366        @NotNull
367        public JsNode visitIsExpression(@NotNull KtIsExpression expression,
368                @NotNull TranslationContext context) {
369            return Translation.patternTranslator(context).translateIsExpression(expression);
370        }
371    
372        @Override
373        @NotNull
374        public JsNode visitSafeQualifiedExpression(@NotNull KtSafeQualifiedExpression expression,
375                @NotNull TranslationContext context) {
376            return QualifiedExpressionTranslator.translateQualifiedExpression(expression, context).source(expression);
377        }
378    
379        @Override
380        @Nullable
381        public JsNode visitWhenExpression(@NotNull KtWhenExpression expression,
382                @NotNull TranslationContext context) {
383            return WhenTranslator.translate(expression, context);
384        }
385    
386        @Override
387        @NotNull
388        public JsNode visitBinaryWithTypeRHSExpression(
389                @NotNull KtBinaryExpressionWithTypeRHS expression,
390                @NotNull TranslationContext context
391        ) {
392            JsExpression jsExpression;
393    
394            if (PatternTranslator.isCastExpression(expression)) {
395                jsExpression = PatternTranslator.newInstance(context).translateCastExpression(expression);
396            }
397            else {
398                jsExpression = Translation.translateAsExpression(expression.getLeft(), context);
399            }
400    
401            return jsExpression.source(expression);
402        }
403    
404        private static String getReferencedName(KtSimpleNameExpression expression) {
405            return expression.getReferencedName()
406                    .replaceAll("^@", "")
407                    .replaceAll("(?:^`(.*)`$)", "$1");
408        }
409    
410        private static JsNameRef getTargetLabel(KtExpressionWithLabel expression, TranslationContext context) {
411            KtSimpleNameExpression labelElement = expression.getTargetLabel();
412            if (labelElement == null) {
413                return null;
414            }
415    
416            String labelIdent = getReferencedName(labelElement);
417            JsScope scope = context.scope();
418            assert scope instanceof JsFunctionScope: "Labeled statement is unexpected outside of function scope";
419            JsName labelName = ((JsFunctionScope) scope).findLabel(labelIdent);
420            assert labelName != null;
421            return labelName.makeRef();
422        }
423    
424        @Override
425        @NotNull
426        public JsNode visitBreakExpression(@NotNull KtBreakExpression expression, @NotNull TranslationContext context) {
427            return new JsBreak(getTargetLabel(expression, context)).source(expression);
428        }
429    
430        @Override
431        @NotNull
432        public JsNode visitContinueExpression(@NotNull KtContinueExpression expression, @NotNull TranslationContext context) {
433            return new JsContinue(getTargetLabel(expression, context)).source(expression);
434        }
435    
436        @Override
437        @NotNull
438        public JsNode visitLambdaExpression(@NotNull KtLambdaExpression expression, @NotNull TranslationContext context) {
439            return new LiteralFunctionTranslator(context).translate(expression.getFunctionLiteral());
440        }
441    
442        @Override
443        @NotNull
444        public JsNode visitNamedFunction(@NotNull KtNamedFunction expression, @NotNull TranslationContext context) {
445            JsExpression alias = new LiteralFunctionTranslator(context).translate(expression);
446    
447            FunctionDescriptor descriptor = getFunctionDescriptor(context.bindingContext(), expression);
448            JsName name = context.getNameForDescriptor(descriptor);
449            if (InlineUtil.isInline(descriptor)) {
450                MetadataProperties.setStaticRef(name, alias);
451            }
452    
453            boolean isExpression = BindingContextUtilsKt.isUsedAsExpression(expression, context.bindingContext());
454            JsNode result = isExpression ? alias : JsAstUtils.newVar(name, alias);
455    
456            return result.source(expression);
457        }
458    
459        @Override
460        @NotNull
461        public JsNode visitThisExpression(@NotNull KtThisExpression expression, @NotNull TranslationContext context) {
462            DeclarationDescriptor thisExpression =
463                    getDescriptorForReferenceExpression(context.bindingContext(), expression.getInstanceReference());
464            assert thisExpression != null : "This expression must reference a descriptor: " + expression.getText();
465    
466            return context.getDispatchReceiver(getReceiverParameterForDeclaration(thisExpression)).source(expression);
467        }
468    
469        @Override
470        @NotNull
471        public JsNode visitArrayAccessExpression(@NotNull KtArrayAccessExpression expression,
472                @NotNull TranslationContext context) {
473            return AccessTranslationUtils.translateAsGet(expression, context);
474        }
475    
476        @Override
477        @NotNull
478        public JsNode visitSuperExpression(@NotNull KtSuperExpression expression, @NotNull TranslationContext context) {
479            ResolvedCall<? extends CallableDescriptor> resolvedCall = getResolvedCallWithAssert(expression, context.bindingContext());
480            return context.getDispatchReceiver((ReceiverParameterDescriptor) resolvedCall.getResultingDescriptor());
481        }
482    
483        @Override
484        @NotNull
485        public JsNode visitForExpression(@NotNull KtForExpression expression,
486                @NotNull TranslationContext context) {
487            return LoopTranslator.translateForExpression(expression, context).source(expression);
488        }
489    
490        @Override
491        @NotNull
492        public JsNode visitTryExpression(
493                @NotNull KtTryExpression expression,
494                @NotNull TranslationContext context
495        ) {
496            return new TryTranslator(expression, context).translate();
497        }
498    
499        @Override
500        @NotNull
501        public JsNode visitThrowExpression(@NotNull KtThrowExpression expression,
502                @NotNull TranslationContext context) {
503            KtExpression thrownExpression = expression.getThrownExpression();
504            assert thrownExpression != null : "Thrown expression must not be null";
505            return new JsThrow(translateAsExpression(thrownExpression, context)).source(expression);
506        }
507    
508        @Override
509        @NotNull
510        public JsNode visitObjectLiteralExpression(@NotNull KtObjectLiteralExpression expression, @NotNull TranslationContext context) {
511            ClassDescriptor descriptor = BindingUtils.getClassDescriptor(context.bindingContext(), expression.getObjectDeclaration());
512            ClassTranslator.TranslationResult result = translateClassOrObject(expression.getObjectDeclaration(), descriptor, context);
513            List<JsPropertyInitializer> properties = result.getProperties();
514            context.getDefinitionPlace().getProperties().addAll(properties);
515    
516            JsExpression constructor = context.getQualifiedReference(descriptor);
517            List<DeclarationDescriptor> closure = context.getClassOrConstructorClosure(descriptor);
518            List<JsExpression> closureArgs = new ArrayList<JsExpression>();
519            if (closure != null) {
520                for (DeclarationDescriptor capturedValue : closure) {
521                    closureArgs.add(context.getArgumentForClosureConstructor(capturedValue));
522                }
523            }
524    
525            // In case of object expressions like this:
526            //   object : SuperClass(A, B, ...)
527            // we may capture local variables in expressions A, B, etc. We don't want to generate local fields for these variables.
528            // Our ClassTranslator is capable of such thing, but case of object expression is a little special.
529            // Consider the following:
530            //
531            //   class A(val x: Int) {
532            //      fun foo() { object : A(x) }
533            //
534            // By calling A(x) super constructor we capture `this` explicitly. However, we can't tell which `A::this` we are mentioning,
535            // either `this` of an object literal or `this` of enclosing `class A`.
536            // Frontend treats it as `this` of enclosing class declaration, therefore it expects backend to generate
537            // super call in scope of `fun foo()` rather than define inner scope for object's constructor.
538            // Thus we generate this call here rather than relying on ClassTranslator.
539            ResolvedCall<FunctionDescriptor> superCall = BindingUtils.getSuperCall(context.bindingContext(),
540                                                                                   expression.getObjectDeclaration());
541            if (superCall != null) {
542                assert context.getDeclarationDescriptor() != null : "This expression should be inside declaration: " +
543                        PsiUtilsKt.getTextWithLocation(expression);
544                TranslationContext superCallContext = context.newDeclaration(context.getDeclarationDescriptor(), result.getDefinitionPlace());
545                closureArgs.addAll(CallArgumentTranslator.translate(superCall, null, superCallContext).getTranslateArguments());
546            }
547    
548            return new JsNew(constructor, closureArgs);
549        }
550    
551        @Override
552        public JsNode visitAnnotatedExpression(@NotNull KtAnnotatedExpression expression, TranslationContext context) {
553            for (KtAnnotationEntry entry : expression.getAnnotationEntries()) {
554                AnnotationDescriptor descriptor = context.bindingContext().get(BindingContext.ANNOTATION, entry);
555                if (descriptor == null) continue;
556    
557                ClassifierDescriptor classifierDescriptor = descriptor.getType().getConstructor().getDeclarationDescriptor();
558                if (classifierDescriptor == null) continue;
559    
560                KotlinRetention retention = DescriptorUtilsKt.getAnnotationRetention(classifierDescriptor);
561    
562                if (retention == KotlinRetention.SOURCE) {
563                    KtExpression baseExpression = expression.getBaseExpression();
564                    if (baseExpression == null) continue;
565    
566                    return baseExpression.accept(this, context);
567                }
568            }
569    
570            return super.visitAnnotatedExpression(expression, context);
571        }
572    
573        @Override
574        public JsNode visitClass(@NotNull KtClass klass, TranslationContext context) {
575            ClassDescriptor descriptor = BindingUtils.getClassDescriptor(context.bindingContext(), klass);
576            context.getDefinitionPlace().getProperties().addAll(translateClassOrObject(klass, descriptor, context).getProperties());
577            return JsEmpty.INSTANCE;
578        }
579    
580        private static ClassTranslator.TranslationResult translateClassOrObject(
581                @NotNull KtClassOrObject declaration,
582                @NotNull ClassDescriptor descriptor,
583                @NotNull TranslationContext context
584        ) {
585            JsScope scope = context.getScopeForDescriptor(descriptor);
586            TranslationContext classContext = context.innerWithUsageTracker(scope, descriptor);
587            return ClassTranslator.translate(declaration, classContext);
588        }
589    }