001 /*
002 * Copyright 2010-2013 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.jet.lang.cfg;
018
019 import com.google.common.collect.Lists;
020 import com.intellij.psi.PsiElement;
021 import com.intellij.psi.tree.IElementType;
022 import org.jetbrains.annotations.NotNull;
023 import org.jetbrains.annotations.Nullable;
024 import org.jetbrains.jet.JetNodeTypes;
025 import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowInstructionsGenerator;
026 import org.jetbrains.jet.lang.cfg.pseudocode.LocalDeclarationInstruction;
027 import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode;
028 import org.jetbrains.jet.lang.cfg.pseudocode.PseudocodeImpl;
029 import org.jetbrains.jet.lang.psi.*;
030 import org.jetbrains.jet.lang.resolve.BindingContext;
031 import org.jetbrains.jet.lang.resolve.BindingTrace;
032 import org.jetbrains.jet.lang.resolve.constants.BooleanValue;
033 import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstantResolver;
034 import org.jetbrains.jet.lang.types.JetType;
035 import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
036 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
037 import org.jetbrains.jet.lexer.JetTokens;
038
039 import java.util.Collection;
040 import java.util.Iterator;
041 import java.util.LinkedList;
042 import java.util.List;
043
044 import static org.jetbrains.jet.lang.diagnostics.Errors.*;
045
046 public class JetControlFlowProcessor {
047
048 private final JetControlFlowBuilder builder;
049 private final BindingTrace trace;
050
051 public JetControlFlowProcessor(BindingTrace trace) {
052 this.builder = new JetControlFlowInstructionsGenerator();
053 this.trace = trace;
054 }
055
056 public Pseudocode generatePseudocode(@NotNull JetElement subroutine) {
057 Pseudocode pseudocode = generate(subroutine);
058 ((PseudocodeImpl) pseudocode).postProcess();
059 for (LocalDeclarationInstruction localDeclarationInstruction : pseudocode.getLocalDeclarations()) {
060 ((PseudocodeImpl)localDeclarationInstruction.getBody()).postProcess();
061 }
062 return pseudocode;
063 }
064
065 private Pseudocode generate(@NotNull JetElement subroutine) {
066 builder.enterSubroutine(subroutine);
067 CFPVisitor cfpVisitor = new CFPVisitor(false);
068 if (subroutine instanceof JetDeclarationWithBody) {
069 JetDeclarationWithBody declarationWithBody = (JetDeclarationWithBody) subroutine;
070 List<JetParameter> valueParameters = declarationWithBody.getValueParameters();
071 for (JetParameter valueParameter : valueParameters) {
072 cfpVisitor.generateInstructions(valueParameter);
073 }
074 JetExpression bodyExpression = declarationWithBody.getBodyExpression();
075 if (bodyExpression != null) {
076 cfpVisitor.generateInstructions(bodyExpression);
077 }
078 } else {
079 cfpVisitor.generateInstructions(subroutine);
080 }
081 return builder.exitSubroutine(subroutine);
082 }
083
084 private void processLocalDeclaration(@NotNull JetDeclaration subroutine) {
085 Label afterDeclaration = builder.createUnboundLabel();
086 builder.nondeterministicJump(afterDeclaration);
087 generate(subroutine);
088 builder.bindLabel(afterDeclaration);
089 }
090
091
092 private class CFPVisitor extends JetVisitorVoid {
093 private final boolean inCondition;
094 private final JetVisitorVoid conditionVisitor = new JetVisitorVoid() {
095
096 @Override
097 public void visitWhenConditionInRange(@NotNull JetWhenConditionInRange condition) {
098 generateInstructions(condition.getRangeExpression(), CFPVisitor.this.inCondition); // TODO : inCondition?
099 generateInstructions(condition.getOperationReference(), CFPVisitor.this.inCondition); // TODO : inCondition?
100 // TODO : read the call to contains()...
101 }
102
103 @Override
104 public void visitWhenConditionIsPattern(@NotNull JetWhenConditionIsPattern condition) {
105 // TODO: types in CF?
106 }
107
108 @Override
109 public void visitWhenConditionWithExpression(@NotNull JetWhenConditionWithExpression condition) {
110 generateInstructions(condition.getExpression(), inCondition);
111 }
112
113 @Override
114 public void visitJetElement(@NotNull JetElement element) {
115 throw new UnsupportedOperationException("[JetControlFlowProcessor] " + element.toString());
116 }
117 };
118
119 private CFPVisitor(boolean inCondition) {
120 this.inCondition = inCondition;
121 }
122
123 public void generateInstructions(@Nullable JetElement element) {
124 generateInstructions(element, inCondition);
125 }
126
127 private void generateInstructions(@Nullable JetElement element, boolean inCondition) {
128 if (element == null) return;
129 CFPVisitor visitor;
130 if (this.inCondition == inCondition) {
131 visitor = this;
132 }
133 else {
134 visitor = new CFPVisitor(inCondition);
135 }
136 element.accept(visitor);
137 checkNothingType(element);
138 }
139
140 private void checkNothingType(JetElement element) {
141 if (!(element instanceof JetExpression)) return;
142 JetExpression expression = JetPsiUtil.deparenthesize((JetExpression) element);
143 if (expression instanceof JetStatementExpression || expression instanceof JetTryExpression
144 || expression instanceof JetIfExpression || expression instanceof JetWhenExpression) {
145 return;
146 }
147
148 JetType type = trace.getBindingContext().get(BindingContext.EXPRESSION_TYPE, expression);
149 if (type != null && KotlinBuiltIns.getInstance().isNothing(type)) {
150 builder.jumpToError();
151 }
152 }
153
154 @Override
155 public void visitParenthesizedExpression(@NotNull JetParenthesizedExpression expression) {
156 builder.read(expression);
157
158 JetExpression innerExpression = expression.getExpression();
159 if (innerExpression != null) {
160 generateInstructions(innerExpression, inCondition);
161 }
162 }
163
164 @Override
165 public void visitAnnotatedExpression(@NotNull JetAnnotatedExpression expression) {
166 builder.read(expression);
167
168 JetExpression baseExpression = expression.getBaseExpression();
169 if (baseExpression != null) {
170 generateInstructions(baseExpression, inCondition);
171 }
172 }
173
174 @Override
175 public void visitThisExpression(@NotNull JetThisExpression expression) {
176 builder.read(expression);
177 }
178
179 @Override
180 public void visitConstantExpression(@NotNull JetConstantExpression expression) {
181 builder.read(expression);
182 }
183
184 @Override
185 public void visitSimpleNameExpression(@NotNull JetSimpleNameExpression expression) {
186 builder.read(expression);
187 }
188
189 @Override
190 public void visitLabelQualifiedExpression(@NotNull JetLabelQualifiedExpression expression) {
191 String labelName = expression.getLabelName();
192 JetExpression labeledExpression = expression.getLabeledExpression();
193 if (labelName != null && labeledExpression != null) {
194 visitLabeledExpression(labelName, labeledExpression);
195 }
196 }
197
198 private void visitLabeledExpression(@NotNull String labelName, @NotNull JetExpression labeledExpression) {
199 JetExpression deparenthesized = JetPsiUtil.deparenthesize(labeledExpression);
200 if (deparenthesized != null) {
201 generateInstructions(labeledExpression, inCondition);
202 }
203 }
204
205 @SuppressWarnings("SuspiciousMethodCalls") @Override
206 public void visitBinaryExpression(@NotNull JetBinaryExpression expression) {
207 IElementType operationType = expression.getOperationReference().getReferencedNameElementType();
208 JetExpression right = expression.getRight();
209 if (operationType == JetTokens.ANDAND) {
210 generateInstructions(expression.getLeft(), true);
211 Label resultLabel = builder.createUnboundLabel();
212 builder.jumpOnFalse(resultLabel);
213 if (right != null) {
214 generateInstructions(right, true);
215 }
216 builder.bindLabel(resultLabel);
217 if (!inCondition) {
218 builder.read(expression);
219 }
220 }
221 else if (operationType == JetTokens.OROR) {
222 generateInstructions(expression.getLeft(), true);
223 Label resultLabel = builder.createUnboundLabel();
224 builder.jumpOnTrue(resultLabel);
225 if (right != null) {
226 generateInstructions(right, true);
227 }
228 builder.bindLabel(resultLabel);
229 if (!inCondition) {
230 builder.read(expression);
231 }
232 }
233 else if (operationType == JetTokens.EQ) {
234 JetExpression left = JetPsiUtil.deparenthesize(expression.getLeft());
235 if (right != null) {
236 generateInstructions(right, false);
237 }
238 if (left instanceof JetSimpleNameExpression) {
239 builder.write(expression, left);
240 }
241 else if (left instanceof JetArrayAccessExpression) {
242 JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) left;
243 visitAssignToArrayAccess(expression, arrayAccessExpression);
244 }
245 else if (left instanceof JetQualifiedExpression) {
246 JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) left;
247 generateInstructions(qualifiedExpression.getReceiverExpression(), false);
248 generateInstructions(expression.getOperationReference(), false);
249 builder.write(expression, left);
250 }
251 else {
252 builder.unsupported(expression); // TODO
253 }
254 }
255 else if (OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(operationType)) {
256 JetExpression left = JetPsiUtil.deparenthesize(expression.getLeft());
257 if (left != null) {
258 generateInstructions(left, false);
259 }
260 if (right != null) {
261 generateInstructions(right, false);
262 }
263 if (left instanceof JetSimpleNameExpression || left instanceof JetArrayAccessExpression) {
264 generateInstructions(expression.getOperationReference(), false);
265 builder.write(expression, left);
266 }
267 else if (left != null) {
268 builder.unsupported(expression); // TODO
269 }
270 }
271 else if (operationType == JetTokens.ELVIS) {
272 builder.read(expression);
273 generateInstructions(expression.getLeft(), false);
274 generateInstructions(expression.getOperationReference(), false);
275 Label afterElvis = builder.createUnboundLabel();
276 builder.jumpOnTrue(afterElvis);
277 if (right != null) {
278 generateInstructions(right, false);
279 }
280 builder.bindLabel(afterElvis);
281 }
282 else {
283 generateInstructions(expression.getLeft(), false);
284 if (right != null) {
285 generateInstructions(right, false);
286 }
287 generateInstructions(expression.getOperationReference(), false);
288 builder.read(expression);
289 }
290 }
291
292 private void visitAssignToArrayAccess(JetBinaryExpression expression, JetArrayAccessExpression arrayAccessExpression) {
293 for (JetExpression index : arrayAccessExpression.getIndexExpressions()) {
294 generateInstructions(index, false);
295 }
296 generateInstructions(arrayAccessExpression.getArrayExpression(), false);
297 generateInstructions(expression.getOperationReference(), false);
298 builder.write(expression, arrayAccessExpression); // TODO : ???
299 }
300
301 @Override
302 public void visitUnaryExpression(@NotNull JetUnaryExpression expression) {
303 JetSimpleNameExpression operationSign = expression.getOperationReference();
304 IElementType operationType = operationSign.getReferencedNameElementType();
305 JetExpression baseExpression = expression.getBaseExpression();
306 if (baseExpression == null) return;
307 if (JetTokens.LABELS.contains(operationType)) {
308 String referencedName = operationSign.getReferencedName();
309 visitLabeledExpression(referencedName.substring(1), baseExpression);
310 }
311 else {
312 generateInstructions(baseExpression, false);
313 generateInstructions(operationSign, false);
314
315 boolean incrementOrDecrement = isIncrementOrDecrement(operationType);
316 if (incrementOrDecrement) {
317 builder.write(expression, baseExpression);
318 }
319
320 builder.read(expression);
321 }
322 }
323
324 private boolean isIncrementOrDecrement(IElementType operationType) {
325 return operationType == JetTokens.PLUSPLUS || operationType == JetTokens.MINUSMINUS;
326 }
327
328
329 @Override
330 public void visitIfExpression(@NotNull JetIfExpression expression) {
331 JetExpression condition = expression.getCondition();
332 if (condition != null) {
333 generateInstructions(condition, true);
334 }
335 Label elseLabel = builder.createUnboundLabel();
336 builder.jumpOnFalse(elseLabel);
337 JetExpression thenBranch = expression.getThen();
338 if (thenBranch != null) {
339 generateInstructions(thenBranch, inCondition);
340 }
341 else {
342 builder.readUnit(expression);
343 }
344 Label resultLabel = builder.createUnboundLabel();
345 builder.jump(resultLabel);
346 builder.bindLabel(elseLabel);
347 JetExpression elseBranch = expression.getElse();
348 if (elseBranch != null) {
349 generateInstructions(elseBranch, inCondition);
350 }
351 else {
352 builder.readUnit(expression);
353 }
354 builder.bindLabel(resultLabel);
355 }
356
357 private class FinallyBlockGenerator {
358 private final JetFinallySection finallyBlock;
359 private Label startFinally = null;
360 private Label finishFinally = null;
361
362 private FinallyBlockGenerator(JetFinallySection block) {
363 finallyBlock = block;
364 }
365
366 public void generate() {
367 JetBlockExpression finalExpression = finallyBlock.getFinalExpression();
368 if (finalExpression == null) return;
369 if (startFinally != null) {
370 assert finishFinally != null;
371 builder.repeatPseudocode(startFinally, finishFinally);
372 return;
373 }
374 startFinally = builder.createUnboundLabel("start finally");
375 builder.bindLabel(startFinally);
376 generateInstructions(finalExpression, inCondition);
377 finishFinally = builder.createUnboundLabel("finish finally");
378 builder.bindLabel(finishFinally);
379 }
380 }
381
382
383 @Override
384 public void visitTryExpression(@NotNull JetTryExpression expression) {
385 builder.read(expression);
386 JetFinallySection finallyBlock = expression.getFinallyBlock();
387 final FinallyBlockGenerator finallyBlockGenerator = new FinallyBlockGenerator(finallyBlock);
388 if (finallyBlock != null) {
389 builder.enterTryFinally(new GenerationTrigger() {
390 private boolean working = false;
391
392 @Override
393 public void generate() {
394 // This checks are needed for the case of having e.g. return inside finally: 'try {return} finally{return}'
395 if (working) return;
396 working = true;
397 finallyBlockGenerator.generate();
398 working = false;
399 }
400 });
401 }
402
403 List<JetCatchClause> catchClauses = expression.getCatchClauses();
404 boolean hasCatches = !catchClauses.isEmpty();
405 Label onException = null;
406 if (hasCatches) {
407 onException = builder.createUnboundLabel("onException");
408 builder.nondeterministicJump(onException);
409 }
410 Label onExceptionToFinallyBlock = null;
411 if (finallyBlock != null) {
412 onExceptionToFinallyBlock = builder.createUnboundLabel("onExceptionToFinallyBlock");
413 builder.nondeterministicJump(onExceptionToFinallyBlock);
414 }
415 generateInstructions(expression.getTryBlock(), inCondition);
416
417 Collection<Label> allowDeadLabels = Lists.newArrayList();
418 if (hasCatches) {
419 Label afterCatches = builder.createUnboundLabel("afterCatches");
420 builder.jump(afterCatches);
421
422 builder.bindLabel(onException);
423 LinkedList<Label> catchLabels = Lists.newLinkedList();
424 int catchClausesSize = catchClauses.size();
425 for (int i = 0; i < catchClausesSize - 1; i++) {
426 catchLabels.add(builder.createUnboundLabel("catch " + i));
427 }
428 if (!catchLabels.isEmpty()) {
429 builder.nondeterministicJump(catchLabels);
430 }
431 boolean isFirst = true;
432 for (JetCatchClause catchClause : catchClauses) {
433 if (!isFirst) {
434 builder.bindLabel(catchLabels.remove());
435 }
436 else {
437 isFirst = false;
438 }
439 JetParameter catchParameter = catchClause.getCatchParameter();
440 if (catchParameter != null) {
441 builder.declare(catchParameter);
442 builder.write(catchParameter, catchParameter);
443 }
444 JetExpression catchBody = catchClause.getCatchBody();
445 if (catchBody != null) {
446 generateInstructions(catchBody, false);
447 }
448 builder.jump(afterCatches);
449 }
450
451 builder.bindLabel(afterCatches);
452 }
453
454 if (finallyBlock != null) {
455 builder.exitTryFinally();
456
457 Label skipFinallyToErrorBlock = builder.createUnboundLabel("skipFinallyToErrorBlock");
458 builder.jump(skipFinallyToErrorBlock);
459 builder.bindLabel(onExceptionToFinallyBlock);
460 finallyBlockGenerator.generate();
461 builder.jumpToError();
462 builder.bindLabel(skipFinallyToErrorBlock);
463
464 finallyBlockGenerator.generate();
465 }
466 }
467
468 @Override
469 public void visitWhileExpression(@NotNull JetWhileExpression expression) {
470 builder.read(expression);
471 LoopInfo loopInfo = builder.enterLoop(expression, null, null);
472
473 builder.bindLabel(loopInfo.getConditionEntryPoint());
474 JetExpression condition = expression.getCondition();
475 if (condition != null) {
476 generateInstructions(condition, true);
477 }
478 boolean conditionIsTrueConstant = false;
479 if (condition instanceof JetConstantExpression && condition.getNode().getElementType() == JetNodeTypes.BOOLEAN_CONSTANT) {
480 if (BooleanValue.TRUE == new CompileTimeConstantResolver().getBooleanValue(
481 (JetConstantExpression) condition, KotlinBuiltIns.getInstance().getBooleanType())) {
482 conditionIsTrueConstant = true;
483 }
484 }
485 if (!conditionIsTrueConstant) {
486 builder.jumpOnFalse(loopInfo.getExitPoint());
487 }
488
489 builder.bindLabel(loopInfo.getBodyEntryPoint());
490 JetExpression body = expression.getBody();
491 if (body != null) {
492 generateInstructions(body, false);
493 }
494 builder.jump(loopInfo.getEntryPoint());
495 builder.exitLoop(expression);
496 builder.readUnit(expression);
497 }
498
499 @Override
500 public void visitDoWhileExpression(@NotNull JetDoWhileExpression expression) {
501 builder.read(expression);
502 LoopInfo loopInfo = builder.enterLoop(expression, null, null);
503
504 builder.bindLabel(loopInfo.getBodyEntryPoint());
505 JetExpression body = expression.getBody();
506 if (body != null) {
507 generateInstructions(body, false);
508 }
509 builder.bindLabel(loopInfo.getConditionEntryPoint());
510 JetExpression condition = expression.getCondition();
511 if (condition != null) {
512 generateInstructions(condition, true);
513 }
514 builder.jumpOnTrue(loopInfo.getEntryPoint());
515 builder.exitLoop(expression);
516 builder.readUnit(expression);
517 }
518
519 @Override
520 public void visitForExpression(@NotNull JetForExpression expression) {
521 builder.read(expression);
522 JetExpression loopRange = expression.getLoopRange();
523 if (loopRange != null) {
524 generateInstructions(loopRange, false);
525 }
526 JetParameter loopParameter = expression.getLoopParameter();
527 if (loopParameter != null) {
528 generateInstructions(loopParameter, inCondition);
529 }
530 else {
531 JetMultiDeclaration multiParameter = expression.getMultiParameter();
532 generateInstructions(multiParameter, inCondition);
533 }
534
535 // TODO : primitive cases
536 Label loopExitPoint = builder.createUnboundLabel();
537 Label conditionEntryPoint = builder.createUnboundLabel();
538
539 builder.bindLabel(conditionEntryPoint);
540 builder.nondeterministicJump(loopExitPoint);
541
542 LoopInfo loopInfo = builder.enterLoop(expression, loopExitPoint, conditionEntryPoint);
543
544 builder.bindLabel(loopInfo.getBodyEntryPoint());
545 JetExpression body = expression.getBody();
546 if (body != null) {
547 generateInstructions(body, false);
548 }
549
550 builder.nondeterministicJump(loopInfo.getEntryPoint());
551 builder.exitLoop(expression);
552 builder.readUnit(expression);
553 }
554
555 @Override
556 public void visitBreakExpression(@NotNull JetBreakExpression expression) {
557 JetElement loop = getCorrespondingLoop(expression);
558 if (loop != null) {
559 builder.jump(builder.getExitPoint(loop));
560 }
561 }
562
563 @Override
564 public void visitContinueExpression(@NotNull JetContinueExpression expression) {
565 JetElement loop = getCorrespondingLoop(expression);
566 if (loop != null) {
567 builder.jump(builder.getEntryPoint(loop));
568 }
569 }
570
571 private JetElement getCorrespondingLoop(JetLabelQualifiedExpression expression) {
572 String labelName = expression.getLabelName();
573 JetElement loop;
574 if (labelName != null) {
575 JetSimpleNameExpression targetLabel = expression.getTargetLabel();
576 assert targetLabel != null;
577 PsiElement labeledElement = trace.get(BindingContext.LABEL_TARGET, targetLabel);
578 if (labeledElement instanceof JetLoopExpression) {
579 loop = (JetLoopExpression) labeledElement;
580 }
581 else {
582 trace.report(NOT_A_LOOP_LABEL.on(expression, targetLabel.getText()));
583 loop = null;
584 }
585 }
586 else {
587 loop = builder.getCurrentLoop();
588 if (loop == null) {
589 trace.report(BREAK_OR_CONTINUE_OUTSIDE_A_LOOP.on(expression));
590 }
591 }
592 return loop;
593 }
594
595 @Override
596 public void visitReturnExpression(@NotNull JetReturnExpression expression) {
597 JetExpression returnedExpression = expression.getReturnedExpression();
598 if (returnedExpression != null) {
599 generateInstructions(returnedExpression, false);
600 }
601 JetSimpleNameExpression labelElement = expression.getTargetLabel();
602 JetElement subroutine;
603 String labelName = expression.getLabelName();
604 if (labelElement != null) {
605 assert labelName != null;
606 PsiElement labeledElement = trace.get(BindingContext.LABEL_TARGET, labelElement);
607 if (labeledElement != null) {
608 assert labeledElement instanceof JetElement;
609 subroutine = (JetElement) labeledElement;
610 }
611 else {
612 subroutine = null;
613 }
614 }
615 else {
616 subroutine = builder.getReturnSubroutine();
617 // TODO : a context check
618 }
619
620 if (subroutine instanceof JetFunction || subroutine instanceof JetPropertyAccessor) {
621 if (returnedExpression == null) {
622 builder.returnNoValue(expression, subroutine);
623 }
624 else {
625 builder.returnValue(expression, subroutine);
626 }
627 }
628 }
629
630 @Override
631 public void visitParameter(@NotNull JetParameter parameter) {
632 builder.declare(parameter);
633 JetExpression defaultValue = parameter.getDefaultValue();
634 if (defaultValue != null) {
635 generateInstructions(defaultValue, inCondition);
636 }
637 builder.write(parameter, parameter);
638 }
639
640 @Override
641 public void visitBlockExpression(@NotNull JetBlockExpression expression) {
642 List<JetElement> statements = expression.getStatements();
643 for (JetElement statement : statements) {
644 generateInstructions(statement, false);
645 }
646 if (statements.isEmpty()) {
647 builder.readUnit(expression);
648 }
649 }
650
651 @Override
652 public void visitNamedFunction(@NotNull JetNamedFunction function) {
653 processLocalDeclaration(function);
654 }
655
656 @Override
657 public void visitFunctionLiteralExpression(@NotNull JetFunctionLiteralExpression expression) {
658 JetFunctionLiteral functionLiteral = expression.getFunctionLiteral();
659 processLocalDeclaration(functionLiteral);
660 builder.read(expression);
661 }
662
663 @Override
664 public void visitQualifiedExpression(@NotNull JetQualifiedExpression expression) {
665 generateInstructions(expression.getReceiverExpression(), false);
666 JetExpression selectorExpression = expression.getSelectorExpression();
667 if (selectorExpression != null) {
668 generateInstructions(selectorExpression, false);
669 }
670 builder.read(expression);
671 }
672
673 private void visitCall(JetCallElement call) {
674 for (ValueArgument argument : call.getValueArguments()) {
675 JetExpression argumentExpression = argument.getArgumentExpression();
676 if (argumentExpression != null) {
677 generateInstructions(argumentExpression, false);
678 }
679 }
680
681 for (JetExpression functionLiteral : call.getFunctionLiteralArguments()) {
682 generateInstructions(functionLiteral, false);
683 }
684 }
685
686 @Override
687 public void visitCallExpression(@NotNull JetCallExpression expression) {
688 for (JetTypeProjection typeArgument : expression.getTypeArguments()) {
689 generateInstructions(typeArgument, false);
690 }
691
692 visitCall(expression);
693
694 generateInstructions(expression.getCalleeExpression(), false);
695 builder.read(expression);
696 }
697
698 @Override
699 public void visitProperty(@NotNull JetProperty property) {
700 builder.declare(property);
701 JetExpression initializer = property.getInitializer();
702 if (initializer != null) {
703 generateInstructions(initializer, false);
704 builder.write(property, property);
705 }
706 JetExpression delegate = property.getDelegateExpression();
707 if (delegate != null) {
708 generateInstructions(delegate, false);
709 }
710 for (JetPropertyAccessor accessor : property.getAccessors()) {
711 generateInstructions(accessor, false);
712 }
713 }
714
715 @Override
716 public void visitMultiDeclaration(@NotNull JetMultiDeclaration declaration) {
717 JetExpression initializer = declaration.getInitializer();
718 if (initializer != null) {
719 generateInstructions(initializer, false);
720 }
721 List<JetMultiDeclarationEntry> entries = declaration.getEntries();
722 for (JetMultiDeclarationEntry entry : entries) {
723 builder.declare(entry);
724 builder.write(entry, entry);
725 }
726 }
727
728 @Override
729 public void visitPropertyAccessor(@NotNull JetPropertyAccessor accessor) {
730 processLocalDeclaration(accessor);
731 }
732
733 @Override
734 public void visitBinaryWithTypeRHSExpression(@NotNull JetBinaryExpressionWithTypeRHS expression) {
735 IElementType operationType = expression.getOperationReference().getReferencedNameElementType();
736 if (operationType == JetTokens.COLON || operationType == JetTokens.AS_KEYWORD || operationType == JetTokens.AS_SAFE) {
737 generateInstructions(expression.getLeft(), false);
738 builder.read(expression);
739 }
740 else {
741 visitJetElement(expression);
742 }
743 }
744
745 @Override
746 public void visitThrowExpression(@NotNull JetThrowExpression expression) {
747 JetExpression thrownExpression = expression.getThrownExpression();
748 if (thrownExpression != null) {
749 generateInstructions(thrownExpression, false);
750 }
751 builder.throwException(expression);
752 }
753
754 @Override
755 public void visitArrayAccessExpression(@NotNull JetArrayAccessExpression expression) {
756 for (JetExpression index : expression.getIndexExpressions()) {
757 generateInstructions(index, false);
758 }
759 generateInstructions(expression.getArrayExpression(), false);
760 // TODO : read 'get' or 'set' function
761 builder.read(expression);
762 }
763
764 @Override
765 public void visitIsExpression(@NotNull JetIsExpression expression) {
766 generateInstructions(expression.getLeftHandSide(), inCondition);
767 // no CF for types
768 // TODO : builder.read(expression.getPattern());
769 builder.read(expression);
770 }
771
772 @Override
773 public void visitWhenExpression(@NotNull JetWhenExpression expression) {
774 JetExpression subjectExpression = expression.getSubjectExpression();
775 if (subjectExpression != null) {
776 generateInstructions(subjectExpression, inCondition);
777 }
778 boolean hasElse = false;
779
780 Label doneLabel = builder.createUnboundLabel();
781
782 Label nextLabel = null;
783 for (Iterator<JetWhenEntry> iterator = expression.getEntries().iterator(); iterator.hasNext(); ) {
784 JetWhenEntry whenEntry = iterator.next();
785
786 builder.read(whenEntry);
787
788 boolean isElse = whenEntry.isElse();
789 if (isElse) {
790 hasElse = true;
791 if (iterator.hasNext()) {
792 trace.report(ELSE_MISPLACED_IN_WHEN.on(whenEntry));
793 }
794 }
795 Label bodyLabel = builder.createUnboundLabel();
796
797 JetWhenCondition[] conditions = whenEntry.getConditions();
798 for (int i = 0; i < conditions.length; i++) {
799 JetWhenCondition condition = conditions[i];
800 condition.accept(conditionVisitor);
801 if (i + 1 < conditions.length) {
802 builder.nondeterministicJump(bodyLabel);
803 }
804 }
805
806 if (!isElse) {
807 nextLabel = builder.createUnboundLabel();
808 builder.nondeterministicJump(nextLabel);
809 }
810
811 builder.bindLabel(bodyLabel);
812 generateInstructions(whenEntry.getExpression(), inCondition);
813 builder.jump(doneLabel);
814
815 if (!isElse) {
816 builder.bindLabel(nextLabel);
817 }
818 }
819 builder.bindLabel(doneLabel);
820 if (!hasElse && WhenChecker.mustHaveElse(expression, trace)) {
821 trace.report(NO_ELSE_IN_WHEN.on(expression));
822 }
823 }
824
825 @Override
826 public void visitObjectLiteralExpression(@NotNull JetObjectLiteralExpression expression) {
827 JetObjectDeclaration declaration = expression.getObjectDeclaration();
828 generateInstructions(declaration, inCondition);
829
830 List<JetDeclaration> declarations = declaration.getDeclarations();
831 List<JetDeclaration> functions = Lists.newArrayList();
832 for (JetDeclaration localDeclaration : declarations) {
833 if (!(localDeclaration instanceof JetProperty) && !(localDeclaration instanceof JetClassInitializer)) {
834 functions.add(localDeclaration);
835 }
836 }
837 for (JetDeclaration function : functions) {
838 generateInstructions(function, inCondition);
839 }
840 builder.read(expression);
841 }
842
843 @Override
844 public void visitObjectDeclaration(@NotNull JetObjectDeclaration objectDeclaration) {
845 visitClassOrObject(objectDeclaration);
846 }
847
848 @Override
849 public void visitStringTemplateExpression(@NotNull JetStringTemplateExpression expression) {
850 for (JetStringTemplateEntry entry : expression.getEntries()) {
851 if (entry instanceof JetStringTemplateEntryWithExpression) {
852 JetStringTemplateEntryWithExpression entryWithExpression = (JetStringTemplateEntryWithExpression) entry;
853 generateInstructions(entryWithExpression.getExpression(), false);
854 }
855 }
856 builder.read(expression);
857 }
858
859 @Override
860 public void visitTypeProjection(@NotNull JetTypeProjection typeProjection) {
861 // TODO : Support Type Arguments. Class object may be initialized at this point");
862 }
863
864 @Override
865 public void visitAnonymousInitializer(@NotNull JetClassInitializer classInitializer) {
866 generateInstructions(classInitializer.getBody(), inCondition);
867 }
868
869 private void visitClassOrObject(JetClassOrObject classOrObject) {
870 for (JetDelegationSpecifier specifier : classOrObject.getDelegationSpecifiers()) {
871 generateInstructions(specifier, inCondition);
872 }
873 List<JetDeclaration> declarations = classOrObject.getDeclarations();
874 for (JetDeclaration declaration : declarations) {
875 if (declaration instanceof JetProperty || declaration instanceof JetClassInitializer) {
876 generateInstructions(declaration, inCondition);
877 }
878 }
879 }
880
881 @Override
882 public void visitClass(@NotNull JetClass klass) {
883 List<JetParameter> parameters = klass.getPrimaryConstructorParameters();
884 for (JetParameter parameter : parameters) {
885 generateInstructions(parameter, inCondition);
886 }
887 visitClassOrObject(klass);
888 }
889
890 @Override
891 public void visitDelegationToSuperCallSpecifier(@NotNull JetDelegatorToSuperCall call) {
892 List<? extends ValueArgument> valueArguments = call.getValueArguments();
893 for (ValueArgument valueArgument : valueArguments) {
894 generateInstructions(valueArgument.getArgumentExpression(), inCondition);
895 }
896 }
897
898 @Override
899 public void visitDelegationByExpressionSpecifier(@NotNull JetDelegatorByExpressionSpecifier specifier) {
900 generateInstructions(specifier.getDelegateExpression(), inCondition);
901 }
902
903 @Override
904 public void visitJetFile(@NotNull JetFile file) {
905 for (JetDeclaration declaration : file.getDeclarations()) {
906 if (declaration instanceof JetProperty) {
907 generateInstructions(declaration, inCondition);
908 }
909 }
910 }
911
912 @Override
913 public void visitJetElement(@NotNull JetElement element) {
914 builder.unsupported(element);
915 }
916 }
917 }