@Nullable private Collection<DfaMemoryState> createInitialStates( @NotNull PsiElement psiBlock, @NotNull InstructionVisitor visitor) { PsiElement container = PsiTreeUtil.getParentOfType(psiBlock, PsiClass.class, PsiLambdaExpression.class); if (container != null && (!(container instanceof PsiClass) || PsiUtil.isLocalOrAnonymousClass((PsiClass) container))) { final PsiElement parent = container.getParent(); final PsiCodeBlock block = DfaPsiUtil.getTopmostBlockInSameClass(parent); if (block != null) { final RunnerResult result = analyzeMethod(block, visitor); if (result == RunnerResult.OK) { final Collection<DfaMemoryState> closureStates = myNestedClosures.get(DfaPsiUtil.getTopmostBlockInSameClass(psiBlock)); if (!closureStates.isEmpty()) { return closureStates; } } return null; } } return Collections.singletonList(createMemoryState()); }
@Nullable private static Map<PsiExpression, PsiType> buildDataflowTypeMap(PsiExpression forPlace) { PsiElement scope = DfaPsiUtil.getTopmostBlockInSameClass(forPlace); if (scope == null) { PsiFile file = forPlace.getContainingFile(); if (!(file instanceof PsiCodeFragment)) { return Collections.emptyMap(); } scope = file; } DataFlowRunner runner = new DataFlowRunner() { @NotNull @Override protected DfaMemoryState createMemoryState() { return new ExpressionTypeMemoryState(getFactory()); } }; final ExpressionTypeInstructionVisitor visitor = new ExpressionTypeInstructionVisitor(forPlace); if (runner.analyzeMethod(scope, visitor) == RunnerResult.OK) { return visitor.getResult(); } return null; }
@Nullable private Collection<DfaMemoryState> createInitialStates( @NotNull PsiElement psiBlock, InstructionVisitor visitor) { PsiClass containingClass = PsiTreeUtil.getParentOfType(psiBlock, PsiClass.class); if (containingClass != null && PsiUtil.isLocalOrAnonymousClass(containingClass)) { final PsiElement parent = containingClass.getParent(); final PsiCodeBlock block = DfaPsiUtil.getTopmostBlockInSameClass(parent); if ((parent instanceof PsiNewExpression || parent instanceof PsiDeclarationStatement) && block != null) { final RunnerResult result = analyzeMethod(block, visitor); if (result == RunnerResult.OK) { final Collection<DfaMemoryState> closureStates = myNestedClosures.get(DfaPsiUtil.getTopmostBlockInSameClass(psiBlock)); if (!closureStates.isEmpty()) { return closureStates; } } return null; } } return Arrays.asList(createMemoryState()); }
@NotNull public static Nullness checkNullness( @Nullable final PsiVariable variable, @Nullable final PsiElement context) { if (variable == null || context == null) return Nullness.UNKNOWN; final PsiElement codeBlock = DfaPsiUtil.getEnclosingCodeBlock(variable, context); if (codeBlock == null) { return Nullness.UNKNOWN; } final ValuableInstructionVisitor visitor = new ValuableInstructionVisitor(context); RunnerResult result = new ValuableDataFlowRunner().analyzeMethod(codeBlock, visitor); if (result != RunnerResult.OK) { return Nullness.UNKNOWN; } if (visitor.myNulls.contains(variable) && !visitor.myNotNulls.contains(variable)) return Nullness.NULLABLE; if (visitor.myNotNulls.contains(variable) && !visitor.myNulls.contains(variable)) return Nullness.NOT_NULL; return Nullness.UNKNOWN; }
@Nullable("null means DFA analysis has failed (too complex to analyze)") public static Collection<PsiExpression> getCachedVariableValues( @Nullable final PsiVariable variable, @Nullable final PsiElement context) { if (variable == null || context == null) return Collections.emptyList(); CachedValue<MultiValuesMap<PsiVariable, PsiExpression>> cachedValue = context.getUserData(DFA_VARIABLE_INFO_KEY); if (cachedValue == null) { final PsiElement codeBlock = DfaPsiUtil.getEnclosingCodeBlock(variable, context); cachedValue = CachedValuesManager.getManager(context.getProject()) .createCachedValue( new CachedValueProvider<MultiValuesMap<PsiVariable, PsiExpression>>() { @Override public Result<MultiValuesMap<PsiVariable, PsiExpression>> compute() { final MultiValuesMap<PsiVariable, PsiExpression> result; if (codeBlock == null) { result = null; } else { final ValuableInstructionVisitor visitor = new ValuableInstructionVisitor(context); RunnerResult runnerResult = new ValuableDataFlowRunner().analyzeMethod(codeBlock, visitor); if (runnerResult == RunnerResult.OK) { result = visitor.myValues; } else { result = TOO_COMPLEX; } } return new Result<MultiValuesMap<PsiVariable, PsiExpression>>( result, variable); } }, false); context.putUserData(DFA_VARIABLE_INFO_KEY, cachedValue); } final MultiValuesMap<PsiVariable, PsiExpression> value = cachedValue.getValue(); if (value == TOO_COMPLEX) return null; final Collection<PsiExpression> expressions = value == null ? null : value.get(variable); return expressions == null ? Collections.<PsiExpression>emptyList() : expressions; }
@NotNull public static Collection<? extends PsiElement> getPossibleInitializationElements( final PsiElement qualifierExpression) { if (qualifierExpression instanceof PsiMethodCallExpression) { return Collections.singletonList(qualifierExpression); } if (qualifierExpression instanceof PsiReferenceExpression) { final PsiElement targetElement = ((PsiReferenceExpression) qualifierExpression).resolve(); if (!(targetElement instanceof PsiVariable)) { return Collections.emptyList(); } final Collection<? extends PsiElement> variableValues = getCachedVariableValues((PsiVariable) targetElement, qualifierExpression); if (variableValues == null || variableValues.isEmpty()) { return DfaPsiUtil.getVariableAssignmentsInFile( (PsiVariable) targetElement, false, qualifierExpression); } return variableValues; } if (qualifierExpression instanceof PsiLiteralExpression) { return Collections.singletonList(qualifierExpression); } return Collections.emptyList(); }