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 }