CauseItem (MemoryStateChange operandHistory, PsiType type, boolean isInstance) { PsiExpression operand = Objects.requireNonNull(operandHistory.getExpression()); TypeConstraint wanted = TypeConstraints.instanceOf(type); PsiType operandType = operand.getType(); if (operandType != null) { TypeConstraint constraint = TypeConstraints.instanceOf(operandType); String name = JavaAnalysisBundle.message("dfa.find.cause.object.kind.expression"); if (operand instanceof PsiMethodCallExpression) { name = JavaAnalysisBundle.message("dfa.find.cause.object.kind.method.return"); } else if (operand instanceof PsiReferenceExpression) { PsiElement target = ((PsiReferenceExpression)operand).resolve(); if (target != null) { name = JavaElementKind.fromElement(target).subject(); } } String explanation = constraint.getAssignabilityExplanation(wanted, isInstance, name); if (explanation != null) { if (constraint.equals(wanted)) { explanation = JavaAnalysisBundle.message("dfa.find.cause.type.known", name, constraint.toShortString()); } return new CauseItem(explanation, operand); } } DfaValue operandValue = operandHistory.myTopOfStack; FactDefinition<TypeConstraint> fact = operandHistory.findFact(operandValue, FactExtractor.constraint()); String explanation = fact.myFact.getAssignabilityExplanation(wanted, isInstance, JavaAnalysisBundle.message("dfa.find.cause.object.kind.generic")); while (explanation != null) { MemoryStateChange causeLocation = fact.myChange; if (causeLocation == null) break; MemoryStateChange prevHistory = causeLocation.getPrevious(); if (prevHistory == null) break; fact = prevHistory.findFact(operandValue, FactExtractor.constraint()); TypeConstraint prevConstraint = fact.myFact; String prevExplanation = prevConstraint.getAssignabilityExplanation(wanted, isInstance, JavaAnalysisBundle.message("dfa.find.cause.object.kind.generic")); if (prevExplanation == null) { if (causeLocation.myInstruction instanceof AssignInstruction && causeLocation.myTopOfStack == operandValue) { PsiExpression rExpression = ((AssignInstruction)causeLocation.myInstruction).getRExpression(); if (rExpression != null) { MemoryStateChange rValuePush = causeLocation.findSubExpressionPush(rExpression); if (rValuePush != null) { CauseItem assignmentItem = createAssignmentCause((AssignInstruction)causeLocation.myInstruction, operandValue); assignmentItem.addChildren(findTypeCause(rValuePush, type, isInstance)); return assignmentItem; } } } CauseItem causeItem = new CauseItem(explanation, operand); causeItem.addChildren( new CauseItem(JavaAnalysisBundle.message("dfa.find.cause.type.is.known.from.place", operand.getText()), causeLocation)); return causeItem; } explanation = prevExplanation; } return null; }