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 }