001 /* 002 * Copyright 2010-2015 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.cfg; 018 019 import com.google.common.collect.ImmutableList; 020 import com.google.common.collect.Lists; 021 import com.google.common.collect.Maps; 022 import com.google.common.collect.Sets; 023 import com.intellij.psi.PsiElement; 024 import com.intellij.psi.tree.IElementType; 025 import com.intellij.psi.util.PsiTreeUtil; 026 import kotlin.Unit; 027 import kotlin.jvm.functions.Function1; 028 import kotlin.jvm.functions.Function3; 029 import org.jetbrains.annotations.NotNull; 030 import org.jetbrains.annotations.Nullable; 031 import org.jetbrains.kotlin.builtins.KotlinBuiltIns; 032 import org.jetbrains.kotlin.cfg.pseudocode.PseudoValue; 033 import org.jetbrains.kotlin.cfg.pseudocode.Pseudocode; 034 import org.jetbrains.kotlin.cfg.pseudocode.PseudocodeUtil; 035 import org.jetbrains.kotlin.cfg.pseudocode.PseudocodeUtilsKt; 036 import org.jetbrains.kotlin.cfg.pseudocode.instructions.Instruction; 037 import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionVisitor; 038 import org.jetbrains.kotlin.cfg.pseudocode.instructions.KtElementInstruction; 039 import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.*; 040 import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.*; 041 import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.LocalFunctionDeclarationInstruction; 042 import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.MarkInstruction; 043 import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.SubroutineExitInstruction; 044 import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.VariableDeclarationInstruction; 045 import org.jetbrains.kotlin.cfg.pseudocodeTraverser.Edges; 046 import org.jetbrains.kotlin.cfg.pseudocodeTraverser.PseudocodeTraverserKt; 047 import org.jetbrains.kotlin.cfg.pseudocodeTraverser.TraversalOrder; 048 import org.jetbrains.kotlin.descriptors.*; 049 import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptorKt; 050 import org.jetbrains.kotlin.diagnostics.Diagnostic; 051 import org.jetbrains.kotlin.diagnostics.DiagnosticFactory; 052 import org.jetbrains.kotlin.diagnostics.Errors; 053 import org.jetbrains.kotlin.idea.MainFunctionDetector; 054 import org.jetbrains.kotlin.lexer.KtTokens; 055 import org.jetbrains.kotlin.psi.*; 056 import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt; 057 import org.jetbrains.kotlin.resolve.*; 058 import org.jetbrains.kotlin.resolve.bindingContextUtil.BindingContextUtilsKt; 059 import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt; 060 import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; 061 import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.ResolvedCallUtilKt; 062 import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue; 063 import org.jetbrains.kotlin.types.KotlinType; 064 import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils; 065 066 import java.util.*; 067 068 import static org.jetbrains.kotlin.cfg.VariableUseState.*; 069 import static org.jetbrains.kotlin.cfg.TailRecursionKind.*; 070 import static org.jetbrains.kotlin.diagnostics.Errors.*; 071 import static org.jetbrains.kotlin.diagnostics.Errors.UNREACHABLE_CODE; 072 import static org.jetbrains.kotlin.resolve.BindingContext.*; 073 import static org.jetbrains.kotlin.types.TypeUtils.DONT_CARE; 074 import static org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE; 075 import static org.jetbrains.kotlin.types.TypeUtils.noExpectedType; 076 077 public class ControlFlowInformationProvider { 078 079 private final KtElement subroutine; 080 private final Pseudocode pseudocode; 081 private final BindingTrace trace; 082 private PseudocodeVariablesData pseudocodeVariablesData; 083 084 private ControlFlowInformationProvider( 085 @NotNull KtElement declaration, 086 @NotNull BindingTrace trace, 087 @NotNull Pseudocode pseudocode 088 ) { 089 this.subroutine = declaration; 090 this.trace = trace; 091 this.pseudocode = pseudocode; 092 } 093 094 public ControlFlowInformationProvider( 095 @NotNull KtElement declaration, 096 @NotNull BindingTrace trace 097 ) { 098 this(declaration, trace, new ControlFlowProcessor(trace).generatePseudocode(declaration)); 099 } 100 101 public PseudocodeVariablesData getPseudocodeVariablesData() { 102 if (pseudocodeVariablesData == null) { 103 pseudocodeVariablesData = new PseudocodeVariablesData(pseudocode, trace.getBindingContext()); 104 } 105 return pseudocodeVariablesData; 106 } 107 108 public void checkForLocalClassOrObjectMode() { 109 // Local classes and objects are analyzed twice: when TopDownAnalyzer processes it and as a part of its container. 110 // Almost all checks can be done when the container is analyzed 111 // except recording initialized variables (this information is needed for DeclarationChecker). 112 recordInitializedVariables(); 113 } 114 115 public void checkDeclaration() { 116 117 recordInitializedVariables(); 118 119 checkLocalFunctions(); 120 121 markUninitializedVariables(); 122 123 markUnusedVariables(); 124 125 markStatements(); 126 127 markUnusedExpressions(); 128 129 checkIfExpressions(); 130 131 checkWhenExpressions(); 132 } 133 134 public void checkFunction(@Nullable KotlinType expectedReturnType) { 135 UnreachableCode unreachableCode = collectUnreachableCode(); 136 reportUnreachableCode(unreachableCode); 137 138 if (subroutine instanceof KtFunctionLiteral) return; 139 140 checkDefiniteReturn(expectedReturnType != null ? expectedReturnType : NO_EXPECTED_TYPE, unreachableCode); 141 142 markTailCalls(); 143 } 144 145 private void collectReturnExpressions(@NotNull final Collection<KtElement> returnedExpressions) { 146 final Set<Instruction> instructions = Sets.newHashSet(pseudocode.getInstructions()); 147 SubroutineExitInstruction exitInstruction = pseudocode.getExitInstruction(); 148 for (Instruction previousInstruction : exitInstruction.getPreviousInstructions()) { 149 previousInstruction.accept(new InstructionVisitor() { 150 @Override 151 public void visitReturnValue(@NotNull ReturnValueInstruction instruction) { 152 if (instructions.contains(instruction)) { //exclude non-local return expressions 153 returnedExpressions.add(instruction.getElement()); 154 } 155 } 156 157 @Override 158 public void visitReturnNoValue(@NotNull ReturnNoValueInstruction instruction) { 159 if (instructions.contains(instruction)) { 160 returnedExpressions.add(instruction.getElement()); 161 } 162 } 163 164 165 @Override 166 public void visitJump(@NotNull AbstractJumpInstruction instruction) { 167 // Nothing 168 } 169 170 @Override 171 public void visitUnconditionalJump(@NotNull UnconditionalJumpInstruction instruction) { 172 redirectToPrevInstructions(instruction); 173 } 174 175 private void redirectToPrevInstructions(Instruction instruction) { 176 for (Instruction previousInstruction : instruction.getPreviousInstructions()) { 177 previousInstruction.accept(this); 178 } 179 } 180 181 @Override 182 public void visitNondeterministicJump(@NotNull NondeterministicJumpInstruction instruction) { 183 redirectToPrevInstructions(instruction); 184 } 185 186 @Override 187 public void visitMarkInstruction(@NotNull MarkInstruction instruction) { 188 redirectToPrevInstructions(instruction); 189 } 190 191 @Override 192 public void visitInstruction(@NotNull Instruction instruction) { 193 if (instruction instanceof KtElementInstruction) { 194 KtElementInstruction elementInstruction = (KtElementInstruction) instruction; 195 returnedExpressions.add(elementInstruction.getElement()); 196 } 197 else { 198 throw new IllegalStateException(instruction + " precedes the exit point"); 199 } 200 } 201 }); 202 } 203 } 204 205 private void checkLocalFunctions() { 206 for (LocalFunctionDeclarationInstruction localDeclarationInstruction : pseudocode.getLocalDeclarations()) { 207 KtElement element = localDeclarationInstruction.getElement(); 208 if (element instanceof KtDeclarationWithBody) { 209 KtDeclarationWithBody localDeclaration = (KtDeclarationWithBody) element; 210 211 CallableDescriptor functionDescriptor = 212 (CallableDescriptor) trace.getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, localDeclaration); 213 KotlinType expectedType = functionDescriptor != null ? functionDescriptor.getReturnType() : null; 214 215 ControlFlowInformationProvider providerForLocalDeclaration = 216 new ControlFlowInformationProvider(localDeclaration, trace, localDeclarationInstruction.getBody()); 217 218 providerForLocalDeclaration.checkFunction(expectedType); 219 } 220 } 221 } 222 223 public void checkDefiniteReturn(final @NotNull KotlinType expectedReturnType, @NotNull final UnreachableCode unreachableCode) { 224 assert subroutine instanceof KtDeclarationWithBody; 225 KtDeclarationWithBody function = (KtDeclarationWithBody) subroutine; 226 227 if (!function.hasBody()) return; 228 229 List<KtElement> returnedExpressions = Lists.newArrayList(); 230 collectReturnExpressions(returnedExpressions); 231 232 final boolean blockBody = function.hasBlockBody(); 233 234 final boolean[] noReturnError = new boolean[] { false }; 235 for (KtElement returnedExpression : returnedExpressions) { 236 returnedExpression.accept(new KtVisitorVoid() { 237 @Override 238 public void visitReturnExpression(@NotNull KtReturnExpression expression) { 239 if (!blockBody) { 240 trace.report(RETURN_IN_FUNCTION_WITH_EXPRESSION_BODY.on(expression)); 241 } 242 } 243 244 @Override 245 public void visitKtElement(@NotNull KtElement element) { 246 if (!(element instanceof KtExpression || element instanceof KtWhenCondition)) return; 247 248 if (blockBody && !noExpectedType(expectedReturnType) 249 && !KotlinBuiltIns.isUnit(expectedReturnType) 250 && !unreachableCode.getElements().contains(element)) { 251 noReturnError[0] = true; 252 } 253 } 254 }); 255 } 256 if (noReturnError[0]) { 257 trace.report(NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY.on(function)); 258 } 259 } 260 261 private void reportUnreachableCode(@NotNull UnreachableCode unreachableCode) { 262 for (KtElement element : unreachableCode.getElements()) { 263 trace.report(UNREACHABLE_CODE.on(element, unreachableCode.getUnreachableTextRanges(element))); 264 trace.record(BindingContext.UNREACHABLE_CODE, element, true); 265 } 266 } 267 268 @NotNull 269 private UnreachableCode collectUnreachableCode() { 270 Set<KtElement> reachableElements = Sets.newHashSet(); 271 Set<KtElement> unreachableElements = Sets.newHashSet(); 272 for (Instruction instruction : pseudocode.getInstructionsIncludingDeadCode()) { 273 if (!(instruction instanceof KtElementInstruction) 274 || instruction instanceof LoadUnitValueInstruction 275 || instruction instanceof MergeInstruction 276 || (instruction instanceof MagicInstruction && ((MagicInstruction) instruction).getSynthetic())) continue; 277 278 KtElement element = ((KtElementInstruction) instruction).getElement(); 279 280 if (instruction instanceof JumpInstruction) { 281 boolean isJumpElement = element instanceof KtBreakExpression 282 || element instanceof KtContinueExpression 283 || element instanceof KtReturnExpression 284 || element instanceof KtThrowExpression; 285 if (!isJumpElement) continue; 286 } 287 288 if (instruction.getDead()) { 289 unreachableElements.add(element); 290 } 291 else { 292 reachableElements.add(element); 293 } 294 } 295 return new UnreachableCodeImpl(reachableElements, unreachableElements); 296 } 297 298 //////////////////////////////////////////////////////////////////////////////// 299 // Uninitialized variables analysis 300 301 public void markUninitializedVariables() { 302 final Collection<VariableDescriptor> varWithUninitializedErrorGenerated = Sets.newHashSet(); 303 final Collection<VariableDescriptor> varWithValReassignErrorGenerated = Sets.newHashSet(); 304 final boolean processClassOrObject = subroutine instanceof KtClassOrObject; 305 306 PseudocodeVariablesData pseudocodeVariablesData = getPseudocodeVariablesData(); 307 Map<Instruction, Edges<InitControlFlowInfo>> initializers = 308 pseudocodeVariablesData.getVariableInitializers(); 309 final Set<VariableDescriptor> declaredVariables = pseudocodeVariablesData.getDeclaredVariables(pseudocode, true); 310 final LexicalScopeVariableInfo lexicalScopeVariableInfo = pseudocodeVariablesData.getLexicalScopeVariableInfo(); 311 312 final Map<Instruction, DiagnosticFactory<?>> reportedDiagnosticMap = Maps.newHashMap(); 313 314 PseudocodeTraverserKt.traverse( 315 pseudocode, TraversalOrder.FORWARD, initializers, 316 new InstructionDataAnalyzeStrategy<Map<VariableDescriptor, VariableControlFlowState>>() { 317 @Override 318 public void execute( 319 @NotNull Instruction instruction, 320 @Nullable Map<VariableDescriptor, VariableControlFlowState> in, 321 @Nullable Map<VariableDescriptor, VariableControlFlowState> out 322 ) { 323 assert in != null && out != null; 324 VariableInitContext ctxt = 325 new VariableInitContext(instruction, reportedDiagnosticMap, in, out, lexicalScopeVariableInfo); 326 if (ctxt.variableDescriptor == null) return; 327 if (instruction instanceof ReadValueInstruction) { 328 ReadValueInstruction readValueInstruction = (ReadValueInstruction) instruction; 329 KtElement element = readValueInstruction.getElement(); 330 if (PseudocodeUtil.isThisOrNoDispatchReceiver(readValueInstruction, trace.getBindingContext()) && 331 declaredVariables.contains(ctxt.variableDescriptor)) { 332 checkIsInitialized(ctxt, element, varWithUninitializedErrorGenerated); 333 } 334 return; 335 } 336 if (!(instruction instanceof WriteValueInstruction)) return; 337 WriteValueInstruction writeValueInstruction = (WriteValueInstruction) instruction; 338 KtElement element = writeValueInstruction.getLValue(); 339 if (!(element instanceof KtExpression)) return; 340 boolean error = checkValReassignment(ctxt, (KtExpression) element, writeValueInstruction, 341 varWithValReassignErrorGenerated); 342 if (!error && processClassOrObject) { 343 error = checkAssignmentBeforeDeclaration(ctxt, (KtExpression) element); 344 } 345 if (!error && processClassOrObject) { 346 checkInitializationForCustomSetter(ctxt, (KtExpression) element); 347 } 348 } 349 } 350 ); 351 } 352 353 public void recordInitializedVariables() { 354 PseudocodeVariablesData pseudocodeVariablesData = getPseudocodeVariablesData(); 355 Pseudocode pseudocode = pseudocodeVariablesData.getPseudocode(); 356 Map<Instruction, Edges<InitControlFlowInfo>> initializers = pseudocodeVariablesData.getVariableInitializers(); 357 recordInitializedVariables(pseudocode, initializers); 358 for (LocalFunctionDeclarationInstruction instruction : pseudocode.getLocalDeclarations()) { 359 recordInitializedVariables(instruction.getBody(), initializers); 360 } 361 } 362 363 private boolean isDefinitelyInitialized(@NotNull PropertyDescriptor propertyDescriptor) { 364 if (propertyDescriptor.isLateInit()) return true; 365 if (trace.get(BACKING_FIELD_REQUIRED, propertyDescriptor) == Boolean.TRUE) return false; 366 PsiElement property = DescriptorToSourceUtils.descriptorToDeclaration(propertyDescriptor); 367 if (property instanceof KtProperty && ((KtProperty) property).hasDelegate()) return false; 368 return true; 369 } 370 371 private void checkIsInitialized( 372 @NotNull VariableInitContext ctxt, 373 @NotNull KtElement element, 374 @NotNull Collection<VariableDescriptor> varWithUninitializedErrorGenerated 375 ) { 376 if (!(element instanceof KtSimpleNameExpression)) return; 377 378 379 boolean isDefinitelyInitialized = ctxt.exitInitState.definitelyInitialized(); 380 VariableDescriptor variableDescriptor = ctxt.variableDescriptor; 381 if (!isDefinitelyInitialized && variableDescriptor instanceof PropertyDescriptor) { 382 isDefinitelyInitialized = isDefinitelyInitialized((PropertyDescriptor) variableDescriptor); 383 } 384 if (!isDefinitelyInitialized && !varWithUninitializedErrorGenerated.contains(variableDescriptor)) { 385 if (!(variableDescriptor instanceof PropertyDescriptor)) { 386 varWithUninitializedErrorGenerated.add(variableDescriptor); 387 } 388 if (variableDescriptor instanceof ValueParameterDescriptor) { 389 report(Errors.UNINITIALIZED_PARAMETER.on((KtSimpleNameExpression) element, 390 (ValueParameterDescriptor) variableDescriptor), ctxt); 391 } 392 else { 393 report(Errors.UNINITIALIZED_VARIABLE.on((KtSimpleNameExpression) element, variableDescriptor), ctxt); 394 } 395 } 396 } 397 398 private boolean checkValReassignment( 399 @NotNull VariableInitContext ctxt, 400 @NotNull KtExpression expression, 401 @NotNull WriteValueInstruction writeValueInstruction, 402 @NotNull Collection<VariableDescriptor> varWithValReassignErrorGenerated 403 ) { 404 VariableDescriptor variableDescriptor = ctxt.variableDescriptor; 405 PropertyDescriptor propertyDescriptor = SyntheticFieldDescriptorKt.getReferencedProperty(variableDescriptor); 406 if (KtPsiUtil.isBackingFieldReference(variableDescriptor) && propertyDescriptor != null) { 407 KtPropertyAccessor accessor = PsiTreeUtil.getParentOfType(expression, KtPropertyAccessor.class); 408 if (accessor != null) { 409 DeclarationDescriptor accessorDescriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, accessor); 410 if (propertyDescriptor.getGetter() == accessorDescriptor) { 411 //val can be reassigned through backing field inside its own getter 412 return false; 413 } 414 } 415 } 416 417 boolean mayBeInitializedNotHere = ctxt.enterInitState.mayBeInitialized(); 418 boolean hasBackingField = true; 419 if (variableDescriptor instanceof PropertyDescriptor) { 420 hasBackingField = trace.get(BindingContext.BACKING_FIELD_REQUIRED, (PropertyDescriptor) variableDescriptor); 421 } 422 if (variableDescriptor.isVar() && variableDescriptor instanceof PropertyDescriptor) { 423 DeclarationDescriptor descriptor = BindingContextUtils.getEnclosingDescriptor(trace.getBindingContext(), expression); 424 PropertySetterDescriptor setterDescriptor = ((PropertyDescriptor) variableDescriptor).getSetter(); 425 426 ResolvedCall<? extends CallableDescriptor> resolvedCall = CallUtilKt.getResolvedCall(expression, trace.getBindingContext()); 427 ReceiverValue receiverValue = null; 428 if (resolvedCall != null) { 429 receiverValue = resolvedCall.getDispatchReceiver(); 430 } 431 432 if (Visibilities.isVisible(receiverValue, variableDescriptor, descriptor) && setterDescriptor != null 433 && !Visibilities.isVisible(receiverValue, setterDescriptor, descriptor)) { 434 report(Errors.INVISIBLE_SETTER.on(expression, variableDescriptor, setterDescriptor.getVisibility(), 435 setterDescriptor), ctxt); 436 return true; 437 } 438 } 439 boolean isThisOrNoDispatchReceiver = 440 PseudocodeUtil.isThisOrNoDispatchReceiver(writeValueInstruction, trace.getBindingContext()); 441 if ((mayBeInitializedNotHere || !hasBackingField || !isThisOrNoDispatchReceiver) && !variableDescriptor.isVar()) { 442 boolean hasReassignMethodReturningUnit = false; 443 KtSimpleNameExpression operationReference = null; 444 PsiElement parent = expression.getParent(); 445 if (parent instanceof KtBinaryExpression) { 446 operationReference = ((KtBinaryExpression) parent).getOperationReference(); 447 } 448 else if (parent instanceof KtUnaryExpression) { 449 operationReference = ((KtUnaryExpression) parent).getOperationReference(); 450 } 451 if (operationReference != null) { 452 DeclarationDescriptor descriptor = trace.get(BindingContext.REFERENCE_TARGET, operationReference); 453 if (descriptor instanceof FunctionDescriptor) { 454 if (KotlinBuiltIns.isUnit(((FunctionDescriptor) descriptor).getReturnType())) { 455 hasReassignMethodReturningUnit = true; 456 } 457 } 458 if (descriptor == null) { 459 Collection<? extends DeclarationDescriptor> descriptors = 460 trace.get(BindingContext.AMBIGUOUS_REFERENCE_TARGET, operationReference); 461 if (descriptors != null) { 462 for (DeclarationDescriptor referenceDescriptor : descriptors) { 463 if (KotlinBuiltIns.isUnit(((FunctionDescriptor) referenceDescriptor).getReturnType())) { 464 hasReassignMethodReturningUnit = true; 465 } 466 } 467 } 468 } 469 } 470 if (!hasReassignMethodReturningUnit) { 471 if (!isThisOrNoDispatchReceiver || !varWithValReassignErrorGenerated.contains(variableDescriptor)) { 472 report(Errors.VAL_REASSIGNMENT.on(expression, variableDescriptor), ctxt); 473 } 474 if (isThisOrNoDispatchReceiver) { 475 // try to get rid of repeating VAL_REASSIGNMENT diagnostic only for vars with no receiver 476 // or when receiver is this 477 varWithValReassignErrorGenerated.add(variableDescriptor); 478 } 479 return true; 480 } 481 } 482 return false; 483 } 484 485 private boolean checkAssignmentBeforeDeclaration(@NotNull VariableInitContext ctxt, @NotNull KtExpression expression) { 486 if (!ctxt.enterInitState.isDeclared() && !ctxt.exitInitState.isDeclared() 487 && !ctxt.enterInitState.mayBeInitialized() && ctxt.exitInitState.mayBeInitialized()) { 488 report(Errors.INITIALIZATION_BEFORE_DECLARATION.on(expression, ctxt.variableDescriptor), ctxt); 489 return true; 490 } 491 return false; 492 } 493 494 private boolean checkInitializationForCustomSetter(@NotNull VariableInitContext ctxt, @NotNull KtExpression expression) { 495 VariableDescriptor variableDescriptor = ctxt.variableDescriptor; 496 if (!(variableDescriptor instanceof PropertyDescriptor) 497 || ctxt.enterInitState.mayBeInitialized() 498 || !ctxt.exitInitState.mayBeInitialized() 499 || !variableDescriptor.isVar() 500 || !trace.get(BindingContext.BACKING_FIELD_REQUIRED, (PropertyDescriptor) variableDescriptor) 501 ) { 502 return false; 503 } 504 505 PsiElement property = DescriptorToSourceUtils.descriptorToDeclaration(variableDescriptor); 506 assert property instanceof KtProperty; 507 KtPropertyAccessor setter = ((KtProperty) property).getSetter(); 508 if (((PropertyDescriptor) variableDescriptor).getModality() == Modality.FINAL && (setter == null || !setter.hasBody())) { 509 return false; 510 } 511 512 KtExpression variable = expression; 513 if (expression instanceof KtDotQualifiedExpression) { 514 if (((KtDotQualifiedExpression) expression).getReceiverExpression() instanceof KtThisExpression) { 515 variable = ((KtDotQualifiedExpression) expression).getSelectorExpression(); 516 } 517 } 518 if (variable instanceof KtSimpleNameExpression) { 519 trace.record(IS_UNINITIALIZED, (PropertyDescriptor) variableDescriptor); 520 return true; 521 } 522 return false; 523 } 524 525 private void recordInitializedVariables( 526 @NotNull Pseudocode pseudocode, 527 @NotNull Map<Instruction, Edges<InitControlFlowInfo>> initializersMap 528 ) { 529 Edges<InitControlFlowInfo> initializers = initializersMap.get(pseudocode.getExitInstruction()); 530 if (initializers == null) return; 531 Set<VariableDescriptor> declaredVariables = getPseudocodeVariablesData().getDeclaredVariables(pseudocode, false); 532 for (VariableDescriptor variable : declaredVariables) { 533 if (variable instanceof PropertyDescriptor) { 534 VariableControlFlowState variableControlFlowState = initializers.getIncoming().get(variable); 535 if (variableControlFlowState != null && variableControlFlowState.definitelyInitialized()) continue; 536 trace.record(BindingContext.IS_UNINITIALIZED, (PropertyDescriptor) variable); 537 } 538 } 539 } 540 541 //////////////////////////////////////////////////////////////////////////////// 542 // "Unused variable" & "unused value" analyses 543 544 public void markUnusedVariables() { 545 final PseudocodeVariablesData pseudocodeVariablesData = getPseudocodeVariablesData(); 546 Map<Instruction, Edges<UseControlFlowInfo>> variableStatusData = pseudocodeVariablesData.getVariableUseStatusData(); 547 final Map<Instruction, DiagnosticFactory<?>> reportedDiagnosticMap = Maps.newHashMap(); 548 InstructionDataAnalyzeStrategy<Map<VariableDescriptor, VariableUseState>> variableStatusAnalyzeStrategy = 549 new InstructionDataAnalyzeStrategy<Map<VariableDescriptor, VariableUseState>>() { 550 @Override 551 public void execute( 552 @NotNull Instruction instruction, 553 @Nullable Map<VariableDescriptor, VariableUseState> in, 554 @Nullable Map<VariableDescriptor, VariableUseState> out 555 ) { 556 557 assert in != null && out != null; 558 VariableContext ctxt = new VariableUseContext(instruction, reportedDiagnosticMap, in, out); 559 Set<VariableDescriptor> declaredVariables = 560 pseudocodeVariablesData.getDeclaredVariables(instruction.getOwner(), false); 561 VariableDescriptor variableDescriptor = PseudocodeUtil.extractVariableDescriptorIfAny( 562 instruction, false, trace.getBindingContext()); 563 if (variableDescriptor == null || !declaredVariables.contains(variableDescriptor) 564 || !ExpressionTypingUtils.isLocal(variableDescriptor.getContainingDeclaration(), variableDescriptor)) { 565 return; 566 } 567 VariableUseState variableUseState = in.get(variableDescriptor); 568 if (instruction instanceof WriteValueInstruction) { 569 if (trace.get(CAPTURED_IN_CLOSURE, variableDescriptor) != null) return; 570 KtElement element = ((WriteValueInstruction) instruction).getElement(); 571 if (variableUseState != READ) { 572 if (element instanceof KtBinaryExpression && 573 ((KtBinaryExpression) element).getOperationToken() == KtTokens.EQ) { 574 KtExpression right = ((KtBinaryExpression) element).getRight(); 575 if (right != null) { 576 report(Errors.UNUSED_VALUE.on((KtBinaryExpression) element, right, variableDescriptor), ctxt); 577 } 578 } 579 else if (element instanceof KtPostfixExpression) { 580 IElementType operationToken = 581 ((KtPostfixExpression) element).getOperationReference().getReferencedNameElementType(); 582 if (operationToken == KtTokens.PLUSPLUS || operationToken == KtTokens.MINUSMINUS) { 583 report(Errors.UNUSED_CHANGED_VALUE.on(element, element), ctxt); 584 } 585 } 586 } 587 } 588 else if (instruction instanceof VariableDeclarationInstruction) { 589 KtDeclaration element = ((VariableDeclarationInstruction) instruction).getVariableDeclarationElement(); 590 if (!(element instanceof KtNamedDeclaration)) return; 591 PsiElement nameIdentifier = ((KtNamedDeclaration) element).getNameIdentifier(); 592 if (nameIdentifier == null) return; 593 if (!VariableUseState.isUsed(variableUseState)) { 594 if (KtPsiUtil.isVariableNotParameterDeclaration(element)) { 595 report(Errors.UNUSED_VARIABLE.on((KtNamedDeclaration) element, variableDescriptor), ctxt); 596 } 597 else if (element instanceof KtParameter) { 598 PsiElement owner = element.getParent().getParent(); 599 if (owner instanceof KtPrimaryConstructor) { 600 if (!((KtParameter) element).hasValOrVar()) { 601 KtClassOrObject containingClass = ((KtPrimaryConstructor) owner).getContainingClassOrObject(); 602 DeclarationDescriptor containingClassDescriptor = trace.get( 603 BindingContext.DECLARATION_TO_DESCRIPTOR, containingClass 604 ); 605 if (!DescriptorUtils.isAnnotationClass(containingClassDescriptor)) { 606 report(Errors.UNUSED_PARAMETER.on((KtParameter) element, variableDescriptor), ctxt); 607 } 608 } 609 } 610 else if (owner instanceof KtFunction) { 611 MainFunctionDetector mainFunctionDetector = new MainFunctionDetector(trace.getBindingContext()); 612 boolean isMain = (owner instanceof KtNamedFunction) && mainFunctionDetector.isMain((KtNamedFunction) owner); 613 if (owner instanceof KtFunctionLiteral) return; 614 DeclarationDescriptor descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, owner); 615 assert descriptor instanceof FunctionDescriptor : owner.getText(); 616 FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor; 617 String functionName = functionDescriptor.getName().asString(); 618 KtFunction function = (KtFunction) owner; 619 if (isMain 620 || ModalityKt.isOverridableOrOverrides(functionDescriptor) 621 || function.hasModifier(KtTokens.OVERRIDE_KEYWORD) 622 || "getValue".equals(functionName) || "setValue".equals(functionName) 623 || "propertyDelegated".equals(functionName) 624 ) { 625 return; 626 } 627 report(Errors.UNUSED_PARAMETER.on((KtParameter) element, variableDescriptor), ctxt); 628 } 629 } 630 } 631 else if (variableUseState == ONLY_WRITTEN_NEVER_READ && KtPsiUtil.isVariableNotParameterDeclaration(element)) { 632 report(Errors.ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE.on((KtNamedDeclaration) element, variableDescriptor), ctxt); 633 } 634 else if (variableUseState == WRITTEN_AFTER_READ && element instanceof KtVariableDeclaration) { 635 if (element instanceof KtProperty) { 636 KtExpression initializer = ((KtProperty) element).getInitializer(); 637 if (initializer != null) { 638 report(Errors.VARIABLE_WITH_REDUNDANT_INITIALIZER.on(initializer, variableDescriptor), ctxt); 639 } 640 } 641 else if (element instanceof KtDestructuringDeclarationEntry) { 642 report(VARIABLE_WITH_REDUNDANT_INITIALIZER.on(element, variableDescriptor), ctxt); 643 } 644 } 645 } 646 } 647 }; 648 PseudocodeTraverserKt.traverse(pseudocode, TraversalOrder.BACKWARD, variableStatusData, variableStatusAnalyzeStrategy); 649 } 650 651 //////////////////////////////////////////////////////////////////////////////// 652 // "Unused expressions" in block 653 654 public void markUnusedExpressions() { 655 final Map<Instruction, DiagnosticFactory<?>> reportedDiagnosticMap = Maps.newHashMap(); 656 PseudocodeTraverserKt.traverse( 657 pseudocode, TraversalOrder.FORWARD, new ControlFlowInformationProvider.FunctionVoid1<Instruction>() { 658 @Override 659 public void execute(@NotNull Instruction instruction) { 660 if (!(instruction instanceof KtElementInstruction)) return; 661 662 KtElement element = ((KtElementInstruction)instruction).getElement(); 663 if (!(element instanceof KtExpression)) return; 664 665 if (BindingContextUtilsKt.isUsedAsStatement((KtExpression) element, trace.getBindingContext()) 666 && PseudocodeUtilsKt.getSideEffectFree(instruction)) { 667 VariableContext ctxt = new VariableContext(instruction, reportedDiagnosticMap); 668 report( 669 element instanceof KtLambdaExpression 670 ? Errors.UNUSED_LAMBDA_EXPRESSION.on((KtLambdaExpression) element) 671 : Errors.UNUSED_EXPRESSION.on(element), 672 ctxt 673 ); 674 } 675 } 676 } 677 ); 678 } 679 680 //////////////////////////////////////////////////////////////////////////////// 681 // Statements 682 683 public void markStatements() { 684 PseudocodeTraverserKt.traverse( 685 pseudocode, TraversalOrder.FORWARD, new ControlFlowInformationProvider.FunctionVoid1<Instruction>() { 686 @Override 687 public void execute(@NotNull Instruction instruction) { 688 PseudoValue value = instruction instanceof InstructionWithValue 689 ? ((InstructionWithValue) instruction).getOutputValue() 690 : null; 691 Pseudocode pseudocode = instruction.getOwner(); 692 boolean isUsedAsExpression = !pseudocode.getUsages(value).isEmpty(); 693 for (KtElement element : pseudocode.getValueElements(value)) { 694 trace.record(BindingContext.USED_AS_EXPRESSION, element, isUsedAsExpression); 695 } 696 } 697 } 698 ); 699 } 700 701 public void checkIfExpressions() { 702 PseudocodeTraverserKt.traverse( 703 pseudocode, TraversalOrder.FORWARD, new ControlFlowInformationProvider.FunctionVoid1<Instruction>() { 704 @Override 705 public void execute(@NotNull Instruction instruction) { 706 PseudoValue value = instruction instanceof InstructionWithValue 707 ? ((InstructionWithValue) instruction).getOutputValue() 708 : null; 709 for (KtElement element : instruction.getOwner().getValueElements(value)) { 710 if (!(element instanceof KtIfExpression)) continue; 711 KtIfExpression ifExpression = (KtIfExpression) element; 712 713 if (BindingContextUtilsKt.isUsedAsExpression(ifExpression, trace.getBindingContext())) { 714 KtExpression thenExpression = ifExpression.getThen(); 715 KtExpression elseExpression = ifExpression.getElse(); 716 717 if (thenExpression == null || elseExpression == null) { 718 trace.report(INVALID_IF_AS_EXPRESSION.on(ifExpression)); 719 } 720 else { 721 checkImplicitCastOnConditionalExpression(ifExpression, ImmutableList.of(thenExpression, elseExpression)); 722 } 723 } 724 } 725 } 726 } 727 ); 728 } 729 730 private void checkImplicitCastOnConditionalExpression( 731 @NotNull KtExpression expression, 732 @NotNull Collection<KtExpression> branchExpressions 733 ) { 734 KotlinType expectedExpressionType = trace.get(EXPECTED_EXPRESSION_TYPE, expression); 735 if (expectedExpressionType != null && expectedExpressionType != DONT_CARE) return; 736 737 KotlinType expressionType = trace.getType(expression); 738 if (expressionType == null) { 739 return; 740 } 741 if (KotlinBuiltIns.isAnyOrNullableAny(expressionType)) { 742 for (KtExpression branchExpression : branchExpressions) { 743 if (branchExpression == null) continue; 744 KotlinType branchType = trace.getType(branchExpression); 745 if (branchType == null || KotlinBuiltIns.isAnyOrNullableAny(branchType)) { 746 return; 747 } 748 } 749 for (KtExpression branchExpression : branchExpressions) { 750 if (branchExpression == null) continue; 751 KotlinType branchType = trace.getType(branchExpression); 752 if (branchType == null) continue; 753 if (KotlinBuiltIns.isNothing(branchType)) continue; 754 trace.report(IMPLICIT_CAST_TO_ANY.on(getResultingExpression(branchExpression), branchType, expressionType)); 755 } 756 } 757 } 758 759 private static @NotNull KtExpression getResultingExpression(@NotNull KtExpression expression) { 760 KtExpression finger = expression; 761 while (true) { 762 KtExpression deparenthesized = KtPsiUtil.deparenthesize(finger); 763 deparenthesized = KtPsiUtil.getExpressionOrLastStatementInBlock(deparenthesized); 764 if (deparenthesized == null || deparenthesized == finger) break; 765 finger = deparenthesized; 766 } 767 return finger; 768 } 769 770 public void checkWhenExpressions() { 771 final Map<Instruction, Edges<InitControlFlowInfo>> initializers = pseudocodeVariablesData.getVariableInitializers(); 772 PseudocodeTraverserKt.traverse( 773 pseudocode, TraversalOrder.FORWARD, new ControlFlowInformationProvider.FunctionVoid1<Instruction>() { 774 @Override 775 public void execute(@NotNull Instruction instruction) { 776 if (instruction instanceof MagicInstruction) { 777 MagicInstruction magicInstruction = (MagicInstruction) instruction; 778 if (magicInstruction.getKind() == MagicKind.EXHAUSTIVE_WHEN_ELSE) { 779 Instruction next = magicInstruction.getNext(); 780 if (next instanceof MergeInstruction) { 781 MergeInstruction mergeInstruction = (MergeInstruction) next; 782 if (initializers.containsKey(mergeInstruction) && initializers.containsKey(magicInstruction)) { 783 InitControlFlowInfo mergeInfo = initializers.get(mergeInstruction).getIncoming(); 784 InitControlFlowInfo magicInfo = initializers.get(magicInstruction).getOutgoing(); 785 if (mergeInstruction.getElement() instanceof KtWhenExpression && 786 magicInfo.checkDefiniteInitializationInWhen(mergeInfo)) { 787 trace.record(IMPLICIT_EXHAUSTIVE_WHEN, (KtWhenExpression) mergeInstruction.getElement()); 788 } 789 } 790 } 791 } 792 } 793 PseudoValue value = instruction instanceof InstructionWithValue 794 ? ((InstructionWithValue) instruction).getOutputValue() 795 : null; 796 for (KtElement element : instruction.getOwner().getValueElements(value)) { 797 if (!(element instanceof KtWhenExpression)) continue; 798 KtWhenExpression whenExpression = (KtWhenExpression) element; 799 800 if (BindingContextUtilsKt.isUsedAsExpression(whenExpression, trace.getBindingContext())) { 801 List<KtExpression> branchExpressions = new ArrayList<KtExpression>(whenExpression.getEntries().size()); 802 for (KtWhenEntry whenEntry : whenExpression.getEntries()) { 803 branchExpressions.add(whenEntry.getExpression()); 804 } 805 checkImplicitCastOnConditionalExpression(whenExpression, branchExpressions); 806 } 807 808 if (whenExpression.getElseExpression() != null) continue; 809 810 BindingContext context = trace.getBindingContext(); 811 List<WhenMissingCase> necessaryCases = WhenChecker.getNecessaryCases(whenExpression, context); 812 if (!necessaryCases.isEmpty()) { 813 trace.report(NO_ELSE_IN_WHEN.on(whenExpression, necessaryCases)); 814 } 815 else if (whenExpression.getSubjectExpression() != null) { 816 ClassDescriptor enumClassDescriptor = WhenChecker.getClassDescriptorOfTypeIfEnum( 817 trace.getType(whenExpression.getSubjectExpression())); 818 if (enumClassDescriptor != null) { 819 List<WhenMissingCase> missingCases = WhenChecker.getEnumMissingCases( 820 whenExpression, context, enumClassDescriptor 821 ); 822 if (!missingCases.isEmpty()) { 823 trace.report(NON_EXHAUSTIVE_WHEN.on(whenExpression, missingCases)); 824 } 825 } 826 } 827 } 828 } 829 } 830 ); 831 } 832 833 //////////////////////////////////////////////////////////////////////////////// 834 // Tail calls 835 836 public void markTailCalls() { 837 final DeclarationDescriptor subroutineDescriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, subroutine); 838 if (!(subroutineDescriptor instanceof FunctionDescriptor)) return; 839 if (!((FunctionDescriptor) subroutineDescriptor).isTailrec()) return; 840 841 // finally blocks are copied which leads to multiple diagnostics reported on one instruction 842 class KindAndCall { 843 TailRecursionKind kind; 844 ResolvedCall<?> call; 845 846 KindAndCall(TailRecursionKind kind, ResolvedCall<?> call) { 847 this.kind = kind; 848 this.call = call; 849 } 850 } 851 final Map<KtElement, KindAndCall> calls = new HashMap<KtElement, KindAndCall>(); 852 PseudocodeTraverserKt.traverse( 853 pseudocode, 854 TraversalOrder.FORWARD, 855 new FunctionVoid1<Instruction>() { 856 public void execute(@NotNull Instruction instruction) { 857 if (!(instruction instanceof CallInstruction)) return; 858 CallInstruction callInstruction = (CallInstruction) instruction; 859 860 ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCall(callInstruction.getElement(), trace.getBindingContext()); 861 if (resolvedCall == null) return; 862 863 // is this a recursive call? 864 CallableDescriptor functionDescriptor = resolvedCall.getResultingDescriptor(); 865 if (!functionDescriptor.getOriginal().equals(subroutineDescriptor)) return; 866 867 KtElement element = callInstruction.getElement(); 868 //noinspection unchecked 869 KtExpression parent = PsiTreeUtil.getParentOfType( 870 element, 871 KtTryExpression.class, KtFunction.class, KtAnonymousInitializer.class 872 ); 873 874 if (parent instanceof KtTryExpression) { 875 // We do not support tail calls Collections.singletonMap() try-catch-finally, for simplicity of the mental model 876 // very few cases there would be real tail-calls, and it's often not so easy for the user to see why 877 calls.put(element, new KindAndCall(IN_TRY, resolvedCall)); 878 return; 879 } 880 881 boolean isTail = PseudocodeTraverserKt.traverseFollowingInstructions( 882 callInstruction, 883 new HashSet<Instruction>(), 884 TraversalOrder.FORWARD, 885 new TailRecursionDetector(subroutine, callInstruction) 886 ); 887 888 // A tail call is not allowed to change dispatch receiver 889 // class C { 890 // fun foo(other: C) { 891 // other.foo(this) // not a tail call 892 // } 893 // } 894 boolean sameDispatchReceiver = 895 ResolvedCallUtilKt.hasThisOrNoDispatchReceiver(resolvedCall, trace.getBindingContext()); 896 897 TailRecursionKind kind = isTail && sameDispatchReceiver ? TAIL_CALL : NON_TAIL; 898 899 KindAndCall kindAndCall = calls.get(element); 900 calls.put(element, 901 new KindAndCall( 902 combineKinds(kind, kindAndCall == null ? null : kindAndCall.kind), 903 resolvedCall 904 ) 905 ); 906 } 907 } 908 ); 909 boolean hasTailCalls = false; 910 for (Map.Entry<KtElement, KindAndCall> entry : calls.entrySet()) { 911 KtElement element = entry.getKey(); 912 KindAndCall kindAndCall = entry.getValue(); 913 switch (kindAndCall.kind) { 914 case TAIL_CALL: 915 trace.record(TAIL_RECURSION_CALL, kindAndCall.call, TailRecursionKind.TAIL_CALL); 916 hasTailCalls = true; 917 break; 918 case IN_TRY: 919 trace.report(Errors.TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED.on(element)); 920 break; 921 case NON_TAIL: 922 trace.report(Errors.NON_TAIL_RECURSIVE_CALL.on(element)); 923 break; 924 } 925 } 926 927 if (!hasTailCalls) { 928 trace.report(Errors.NO_TAIL_CALLS_FOUND.on((KtNamedFunction) subroutine)); 929 } 930 } 931 932 private static TailRecursionKind combineKinds(TailRecursionKind kind, @Nullable TailRecursionKind existingKind) { 933 TailRecursionKind resultingKind; 934 if (existingKind == null || existingKind == kind) { 935 resultingKind = kind; 936 } 937 else { 938 if (check(kind, existingKind, IN_TRY, TAIL_CALL)) { 939 resultingKind = IN_TRY; 940 } 941 else if (check(kind, existingKind, IN_TRY, NON_TAIL)) { 942 resultingKind = IN_TRY; 943 } 944 else { 945 // TAIL_CALL, NON_TAIL 946 resultingKind = NON_TAIL; 947 } 948 } 949 return resultingKind; 950 } 951 952 private static boolean check(Object a, Object b, Object x, Object y) { 953 return (a == x && b == y) || (a == y && b == x); 954 } 955 956 //////////////////////////////////////////////////////////////////////////////// 957 // Utility classes and methods 958 959 /** 960 * The method provides reporting of the same diagnostic only once for copied instructions 961 * (depends on whether it should be reported for all or only for one of the copies) 962 */ 963 private void report( 964 @NotNull Diagnostic diagnostic, 965 @NotNull VariableContext ctxt 966 ) { 967 Instruction instruction = ctxt.instruction; 968 if (instruction.getCopies().isEmpty()) { 969 trace.report(diagnostic); 970 return; 971 } 972 Map<Instruction, DiagnosticFactory<?>> previouslyReported = ctxt.reportedDiagnosticMap; 973 previouslyReported.put(instruction, diagnostic.getFactory()); 974 975 boolean alreadyReported = false; 976 boolean sameErrorForAllCopies = true; 977 for (Instruction copy : instruction.getCopies()) { 978 DiagnosticFactory<?> previouslyReportedErrorFactory = previouslyReported.get(copy); 979 if (previouslyReportedErrorFactory != null) { 980 alreadyReported = true; 981 } 982 983 if (previouslyReportedErrorFactory != diagnostic.getFactory()) { 984 sameErrorForAllCopies = false; 985 } 986 } 987 988 if (mustBeReportedOnAllCopies(diagnostic.getFactory())) { 989 if (sameErrorForAllCopies) { 990 trace.report(diagnostic); 991 } 992 } 993 else { 994 //only one reporting required 995 if (!alreadyReported) { 996 trace.report(diagnostic); 997 } 998 } 999 } 1000 1001 private static boolean mustBeReportedOnAllCopies(@NotNull DiagnosticFactory<?> diagnosticFactory) { 1002 return diagnosticFactory == UNUSED_VARIABLE 1003 || diagnosticFactory == UNUSED_PARAMETER 1004 || diagnosticFactory == UNUSED_CHANGED_VALUE; 1005 } 1006 1007 1008 private class VariableContext { 1009 final Map<Instruction, DiagnosticFactory<?>> reportedDiagnosticMap; 1010 final Instruction instruction; 1011 final VariableDescriptor variableDescriptor; 1012 1013 private VariableContext( 1014 @NotNull Instruction instruction, 1015 @NotNull Map<Instruction, DiagnosticFactory<?>> map 1016 ) { 1017 this.instruction = instruction; 1018 reportedDiagnosticMap = map; 1019 variableDescriptor = PseudocodeUtil.extractVariableDescriptorIfAny(instruction, true, trace.getBindingContext()); 1020 } 1021 } 1022 1023 private class VariableInitContext extends VariableContext { 1024 final VariableControlFlowState enterInitState; 1025 final VariableControlFlowState exitInitState; 1026 1027 private VariableInitContext( 1028 @NotNull Instruction instruction, 1029 @NotNull Map<Instruction, DiagnosticFactory<?>> map, 1030 @NotNull Map<VariableDescriptor, VariableControlFlowState> in, 1031 @NotNull Map<VariableDescriptor, VariableControlFlowState> out, 1032 @NotNull LexicalScopeVariableInfo lexicalScopeVariableInfo 1033 ) { 1034 super(instruction, map); 1035 enterInitState = initialize(variableDescriptor, lexicalScopeVariableInfo, in); 1036 exitInitState = initialize(variableDescriptor, lexicalScopeVariableInfo, out); 1037 } 1038 1039 private VariableControlFlowState initialize( 1040 VariableDescriptor variableDescriptor, 1041 LexicalScopeVariableInfo lexicalScopeVariableInfo, 1042 Map<VariableDescriptor, VariableControlFlowState> map 1043 ) { 1044 if (variableDescriptor == null) return null; 1045 VariableControlFlowState state = map.get(variableDescriptor); 1046 if (state != null) return state; 1047 return PseudocodeVariablesData.getDefaultValueForInitializers(variableDescriptor, instruction, lexicalScopeVariableInfo); 1048 } 1049 } 1050 1051 private class VariableUseContext extends VariableContext { 1052 final VariableUseState enterUseState; 1053 final VariableUseState exitUseState; 1054 1055 1056 private VariableUseContext( 1057 @NotNull Instruction instruction, 1058 @NotNull Map<Instruction, DiagnosticFactory<?>> map, 1059 @NotNull Map<VariableDescriptor, VariableUseState> in, 1060 @NotNull Map<VariableDescriptor, VariableUseState> out 1061 ) { 1062 super(instruction, map); 1063 enterUseState = variableDescriptor != null ? in.get(variableDescriptor) : null; 1064 exitUseState = variableDescriptor != null ? out.get(variableDescriptor) : null; 1065 } 1066 } 1067 1068 //TODO after KT-4621 rewrite to Kotlin 1069 public abstract static class InstructionDataAnalyzeStrategy<D> implements Function3<Instruction, D, D, Unit> { 1070 @Override 1071 public Unit invoke(Instruction instruction, D enterData, D exitData) { 1072 execute(instruction, enterData, exitData); 1073 return Unit.INSTANCE; 1074 } 1075 1076 public abstract void execute(Instruction instruction, D enterData, D exitData); 1077 } 1078 1079 public abstract static class FunctionVoid1<P> implements Function1<P, Unit> { 1080 @Override 1081 public Unit invoke(P p) { 1082 execute(p); 1083 return Unit.INSTANCE; 1084 } 1085 1086 public abstract void execute(P p); 1087 } 1088 }