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