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            if (thenStatement == null) {
271                thenStatement = JsEmpty.INSTANCE;
272            }
273            JsIf ifStatement = new JsIf(testExpression, thenStatement, elseStatement);
274            return ifStatement.source(expression);
275        }
276    
277        @Override
278        @NotNull
279        public JsExpression visitSimpleNameExpression(@NotNull KtSimpleNameExpression expression,
280                @NotNull TranslationContext context) {
281            return ReferenceTranslator.translateSimpleName(expression, context).source(expression);
282        }
283    
284        @Override
285        @NotNull
286        public JsNode visitWhileExpression(@NotNull KtWhileExpression expression, @NotNull TranslationContext context) {
287            return LoopTranslator.createWhile(false, expression, context);
288        }
289    
290        @Override
291        @NotNull
292        public JsNode visitDoWhileExpression(@NotNull KtDoWhileExpression expression, @NotNull TranslationContext context) {
293            return LoopTranslator.createWhile(true, expression, context);
294        }
295    
296        @Override
297        @NotNull
298        public JsNode visitStringTemplateExpression(@NotNull KtStringTemplateExpression expression, @NotNull TranslationContext context) {
299            JsStringLiteral stringLiteral = resolveAsStringConstant(expression, context);
300            if (stringLiteral != null) {
301                return stringLiteral;
302            }
303            return resolveAsTemplate(expression, context).source(expression);
304        }
305    
306        @NotNull
307        private static JsNode resolveAsTemplate(@NotNull KtStringTemplateExpression expression,
308                @NotNull TranslationContext context) {
309            return StringTemplateTranslator.translate(expression, context);
310        }
311    
312        @Nullable
313        private static JsStringLiteral resolveAsStringConstant(@NotNull KtExpression expression,
314                @NotNull TranslationContext context) {
315            Object value = getCompileTimeValue(context.bindingContext(), expression);
316            if (value == null) {
317                return null;
318            }
319            assert value instanceof String : "Compile time constant template should be a String constant.";
320            String constantString = (String) value;
321            return context.program().getStringLiteral(constantString);
322        }
323    
324        @Override
325        @NotNull
326        public JsNode visitDotQualifiedExpression(@NotNull KtDotQualifiedExpression expression, @NotNull TranslationContext context) {
327            return QualifiedExpressionTranslator.translateQualifiedExpression(expression, context);
328        }
329    
330        @Override
331        public JsNode visitLabeledExpression(@NotNull KtLabeledExpression expression, @NotNull TranslationContext context) {
332            KtExpression baseExpression = expression.getBaseExpression();
333            assert baseExpression != null;
334    
335            if (BindingContextUtilsKt.isUsedAsExpression(expression, context.bindingContext())) {
336                return Translation.translateAsExpression(baseExpression, context).source(expression);
337            }
338    
339            JsScope scope = context.scope();
340            assert scope instanceof JsFunctionScope: "Labeled statement is unexpected outside of function scope";
341            JsFunctionScope functionScope = (JsFunctionScope) scope;
342    
343            String labelIdent = getReferencedName(expression.getTargetLabel());
344    
345            JsName labelName = functionScope.enterLabel(labelIdent);
346            JsStatement baseStatement = Translation.translateAsStatement(baseExpression, context);
347            functionScope.exitLabel();
348    
349            return new JsLabel(labelName, baseStatement).source(expression);
350        }
351    
352        @Override
353        @NotNull
354        public JsNode visitPrefixExpression(
355                @NotNull KtPrefixExpression expression,
356                @NotNull TranslationContext context
357        ) {
358            return UnaryOperationTranslator.translate(expression, context).source(expression);
359        }
360    
361        @Override
362        @NotNull
363        public JsNode visitPostfixExpression(@NotNull KtPostfixExpression expression,
364                @NotNull TranslationContext context) {
365            return UnaryOperationTranslator.translate(expression, context).source(expression);
366        }
367    
368        @Override
369        @NotNull
370        public JsNode visitIsExpression(@NotNull KtIsExpression expression,
371                @NotNull TranslationContext context) {
372            return Translation.patternTranslator(context).translateIsExpression(expression);
373        }
374    
375        @Override
376        @NotNull
377        public JsNode visitSafeQualifiedExpression(@NotNull KtSafeQualifiedExpression expression,
378                @NotNull TranslationContext context) {
379            return QualifiedExpressionTranslator.translateQualifiedExpression(expression, context).source(expression);
380        }
381    
382        @Override
383        @Nullable
384        public JsNode visitWhenExpression(@NotNull KtWhenExpression expression,
385                @NotNull TranslationContext context) {
386            return WhenTranslator.translate(expression, context);
387        }
388    
389        @Override
390        @NotNull
391        public JsNode visitBinaryWithTypeRHSExpression(
392                @NotNull KtBinaryExpressionWithTypeRHS expression,
393                @NotNull TranslationContext context
394        ) {
395            JsExpression jsExpression;
396    
397            if (PatternTranslator.isCastExpression(expression)) {
398                jsExpression = PatternTranslator.newInstance(context).translateCastExpression(expression);
399            }
400            else {
401                jsExpression = Translation.translateAsExpression(expression.getLeft(), context);
402            }
403    
404            return jsExpression.source(expression);
405        }
406    
407        private static String getReferencedName(KtSimpleNameExpression expression) {
408            return expression.getReferencedName()
409                    .replaceAll("^@", "")
410                    .replaceAll("(?:^`(.*)`$)", "$1");
411        }
412    
413        private static JsNameRef getTargetLabel(KtExpressionWithLabel expression, TranslationContext context) {
414            KtSimpleNameExpression labelElement = expression.getTargetLabel();
415            if (labelElement == null) {
416                return null;
417            }
418    
419            String labelIdent = getReferencedName(labelElement);
420            JsScope scope = context.scope();
421            assert scope instanceof JsFunctionScope: "Labeled statement is unexpected outside of function scope";
422            JsName labelName = ((JsFunctionScope) scope).findLabel(labelIdent);
423            assert labelName != null;
424            return labelName.makeRef();
425        }
426    
427        @Override
428        @NotNull
429        public JsNode visitBreakExpression(@NotNull KtBreakExpression expression, @NotNull TranslationContext context) {
430            return new JsBreak(getTargetLabel(expression, context)).source(expression);
431        }
432    
433        @Override
434        @NotNull
435        public JsNode visitContinueExpression(@NotNull KtContinueExpression expression, @NotNull TranslationContext context) {
436            return new JsContinue(getTargetLabel(expression, context)).source(expression);
437        }
438    
439        @Override
440        @NotNull
441        public JsNode visitLambdaExpression(@NotNull KtLambdaExpression expression, @NotNull TranslationContext context) {
442            return new LiteralFunctionTranslator(context).translate(expression.getFunctionLiteral());
443        }
444    
445        @Override
446        @NotNull
447        public JsNode visitNamedFunction(@NotNull KtNamedFunction expression, @NotNull TranslationContext context) {
448            JsExpression alias = new LiteralFunctionTranslator(context).translate(expression);
449    
450            FunctionDescriptor descriptor = getFunctionDescriptor(context.bindingContext(), expression);
451            JsName name = context.getNameForDescriptor(descriptor);
452            if (InlineUtil.isInline(descriptor)) {
453                MetadataProperties.setStaticRef(name, alias);
454            }
455    
456            boolean isExpression = BindingContextUtilsKt.isUsedAsExpression(expression, context.bindingContext());
457            JsNode result = isExpression ? alias : JsAstUtils.newVar(name, alias);
458    
459            return result.source(expression);
460        }
461    
462        @Override
463        @NotNull
464        public JsNode visitThisExpression(@NotNull KtThisExpression expression, @NotNull TranslationContext context) {
465            DeclarationDescriptor thisExpression =
466                    getDescriptorForReferenceExpression(context.bindingContext(), expression.getInstanceReference());
467            assert thisExpression != null : "This expression must reference a descriptor: " + expression.getText();
468    
469            return context.getDispatchReceiver(getReceiverParameterForDeclaration(thisExpression)).source(expression);
470        }
471    
472        @Override
473        @NotNull
474        public JsNode visitArrayAccessExpression(@NotNull KtArrayAccessExpression expression,
475                @NotNull TranslationContext context) {
476            return AccessTranslationUtils.translateAsGet(expression, context);
477        }
478    
479        @Override
480        @NotNull
481        public JsNode visitSuperExpression(@NotNull KtSuperExpression expression, @NotNull TranslationContext context) {
482            ResolvedCall<? extends CallableDescriptor> resolvedCall = getResolvedCallWithAssert(expression, context.bindingContext());
483            return context.getDispatchReceiver((ReceiverParameterDescriptor) resolvedCall.getResultingDescriptor());
484        }
485    
486        @Override
487        @NotNull
488        public JsNode visitForExpression(@NotNull KtForExpression expression,
489                @NotNull TranslationContext context) {
490            return LoopTranslator.translateForExpression(expression, context).source(expression);
491        }
492    
493        @Override
494        @NotNull
495        public JsNode visitTryExpression(
496                @NotNull KtTryExpression expression,
497                @NotNull TranslationContext context
498        ) {
499            return new TryTranslator(expression, context).translate();
500        }
501    
502        @Override
503        @NotNull
504        public JsNode visitThrowExpression(@NotNull KtThrowExpression expression,
505                @NotNull TranslationContext context) {
506            KtExpression thrownExpression = expression.getThrownExpression();
507            assert thrownExpression != null : "Thrown expression must not be null";
508            return new JsThrow(translateAsExpression(thrownExpression, context)).source(expression);
509        }
510    
511        @Override
512        @NotNull
513        public JsNode visitObjectLiteralExpression(@NotNull KtObjectLiteralExpression expression, @NotNull TranslationContext context) {
514            ClassDescriptor descriptor = BindingUtils.getClassDescriptor(context.bindingContext(), expression.getObjectDeclaration());
515            ClassTranslator.TranslationResult result = translateClassOrObject(expression.getObjectDeclaration(), descriptor, context);
516            List<JsPropertyInitializer> properties = result.getProperties();
517            context.getDefinitionPlace().getProperties().addAll(properties);
518    
519            JsExpression constructor = context.getQualifiedReference(descriptor);
520            List<DeclarationDescriptor> closure = context.getClassOrConstructorClosure(descriptor);
521            List<JsExpression> closureArgs = new ArrayList<JsExpression>();
522            if (closure != null) {
523                for (DeclarationDescriptor capturedValue : closure) {
524                    closureArgs.add(context.getArgumentForClosureConstructor(capturedValue));
525                }
526            }
527    
528            // In case of object expressions like this:
529            //   object : SuperClass(A, B, ...)
530            // we may capture local variables in expressions A, B, etc. We don't want to generate local fields for these variables.
531            // Our ClassTranslator is capable of such thing, but case of object expression is a little special.
532            // Consider the following:
533            //
534            //   class A(val x: Int) {
535            //      fun foo() { object : A(x) }
536            //
537            // By calling A(x) super constructor we capture `this` explicitly. However, we can't tell which `A::this` we are mentioning,
538            // either `this` of an object literal or `this` of enclosing `class A`.
539            // Frontend treats it as `this` of enclosing class declaration, therefore it expects backend to generate
540            // super call in scope of `fun foo()` rather than define inner scope for object's constructor.
541            // Thus we generate this call here rather than relying on ClassTranslator.
542            ResolvedCall<FunctionDescriptor> superCall = BindingUtils.getSuperCall(context.bindingContext(),
543                                                                                   expression.getObjectDeclaration());
544            if (superCall != null) {
545                assert context.getDeclarationDescriptor() != null : "This expression should be inside declaration: " +
546                        PsiUtilsKt.getTextWithLocation(expression);
547                TranslationContext superCallContext = context.newDeclaration(context.getDeclarationDescriptor(), result.getDefinitionPlace());
548                closureArgs.addAll(CallArgumentTranslator.translate(superCall, null, superCallContext).getTranslateArguments());
549            }
550    
551            return new JsNew(constructor, closureArgs);
552        }
553    
554        @Override
555        public JsNode visitAnnotatedExpression(@NotNull KtAnnotatedExpression expression, TranslationContext context) {
556            for (KtAnnotationEntry entry : expression.getAnnotationEntries()) {
557                AnnotationDescriptor descriptor = context.bindingContext().get(BindingContext.ANNOTATION, entry);
558                if (descriptor == null) continue;
559    
560                ClassifierDescriptor classifierDescriptor = descriptor.getType().getConstructor().getDeclarationDescriptor();
561                if (classifierDescriptor == null) continue;
562    
563                KotlinRetention retention = DescriptorUtilsKt.getAnnotationRetention(classifierDescriptor);
564    
565                if (retention == KotlinRetention.SOURCE) {
566                    KtExpression baseExpression = expression.getBaseExpression();
567                    if (baseExpression == null) continue;
568    
569                    return baseExpression.accept(this, context);
570                }
571            }
572    
573            return super.visitAnnotatedExpression(expression, context);
574        }
575    
576        @Override
577        public JsNode visitClass(@NotNull KtClass klass, TranslationContext context) {
578            ClassDescriptor descriptor = BindingUtils.getClassDescriptor(context.bindingContext(), klass);
579            context.getDefinitionPlace().getProperties().addAll(translateClassOrObject(klass, descriptor, context).getProperties());
580            return JsEmpty.INSTANCE;
581        }
582    
583        private static ClassTranslator.TranslationResult translateClassOrObject(
584                @NotNull KtClassOrObject declaration,
585                @NotNull ClassDescriptor descriptor,
586                @NotNull TranslationContext context
587        ) {
588            JsScope scope = context.getScopeForDescriptor(descriptor);
589            TranslationContext classContext = context.innerWithUsageTracker(scope, descriptor);
590            return ClassTranslator.translate(declaration, classContext);
591        }
592    }