@NotNull private static ControlFlow getControlFlow(@NotNull PsiElement context) throws AnalysisCanceledException { LocalsOrMyInstanceFieldsControlFlowPolicy policy = LocalsOrMyInstanceFieldsControlFlowPolicy.getInstance(); return ControlFlowFactory.getInstance(context.getProject()).getControlFlow(context, policy); }
@Override public boolean isValueCompatible() { final PsiElement body = getBody(); if (body != null) { try { final ControlFlow controlFlow = ControlFlowFactory.getInstance(getProject()) .getControlFlow( body, LocalsOrMyInstanceFieldsControlFlowPolicy.getInstance(), false); if (ControlFlowUtil.findExitPointsAndStatements( controlFlow, 0, controlFlow.getSize(), new IntArrayList(), PsiReturnStatement.class, PsiThrowStatement.class) .isEmpty()) { return false; } } catch (AnalysisCanceledException e) { return true; } } return true; }
private static void checkCodeBlock( final PsiCodeBlock body, final Set<PsiField> candidates, Set<PsiField> usedFields) { try { final ControlFlow controlFlow = ControlFlowFactory.getInstance(body.getProject()) .getControlFlow(body, AllVariablesControlFlowPolicy.getInstance()); final List<PsiVariable> usedVars = ControlFlowUtil.getUsedVariables(controlFlow, 0, controlFlow.getSize()); for (PsiVariable usedVariable : usedVars) { if (usedVariable instanceof PsiField) { final PsiField usedField = (PsiField) usedVariable; if (!usedFields.add(usedField)) { candidates.remove(usedField); // used in more than one code block } } } final List<PsiReferenceExpression> readBeforeWrites = ControlFlowUtil.getReadBeforeWrite(controlFlow); for (final PsiReferenceExpression readBeforeWrite : readBeforeWrites) { final PsiElement resolved = readBeforeWrite.resolve(); if (resolved instanceof PsiField) { final PsiField field = (PsiField) resolved; PsiElement parent = body.getParent(); if (!(parent instanceof PsiMethod) || !((PsiMethod) parent).isConstructor() || field.getInitializer() == null || field.hasModifierProperty(PsiModifier.STATIC)) { candidates.remove(field); } } } } catch (AnalysisCanceledException e) { candidates.clear(); } }
@NotNull public static ControlFlow getControlFlowNoConstantEvaluate(@NotNull PsiElement body) throws AnalysisCanceledException { LocalsOrMyInstanceFieldsControlFlowPolicy policy = LocalsOrMyInstanceFieldsControlFlowPolicy.getInstance(); return ControlFlowFactory.getInstance(body.getProject()) .getControlFlow(body, policy, false, false); }
public ControlFlowWrapper(Project project, PsiElement codeFragment, PsiElement[] elements) throws PrepareFailedException { try { myControlFlow = ControlFlowFactory.getInstance(project) .getControlFlow( codeFragment, new LocalsControlFlowPolicy(codeFragment), false, false); } catch (AnalysisCanceledException e) { throw new PrepareFailedException( RefactoringBundle.message("extract.method.control.flow.analysis.failed"), e.getErrorElement()); } if (LOG.isDebugEnabled()) { LOG.debug(myControlFlow.toString()); } int flowStart = -1; int index = 0; while (index < elements.length) { flowStart = myControlFlow.getStartOffset(elements[index]); if (flowStart >= 0) break; index++; } int flowEnd; if (flowStart < 0) { // no executable code flowStart = 0; flowEnd = 0; } else { index = elements.length - 1; while (true) { flowEnd = myControlFlow.getEndOffset(elements[index]); if (flowEnd >= 0) break; index--; } } myFlowStart = flowStart; myFlowEnd = flowEnd; if (LOG.isDebugEnabled()) { LOG.debug("start offset:" + myFlowStart); LOG.debug("end offset:" + myFlowEnd); } }
@Override public boolean isVoidCompatible() { final PsiElement body = getBody(); if (body != null) { try { ControlFlow controlFlow = ControlFlowFactory.getInstance(getProject()) .getControlFlow(body, LocalsOrMyInstanceFieldsControlFlowPolicy.getInstance()); int startOffset = controlFlow.getStartOffset(body); int endOffset = controlFlow.getEndOffset(body); return startOffset != -1 && endOffset != -1 && !ControlFlowUtil.canCompleteNormally(controlFlow, startOffset, endOffset); } catch (AnalysisCanceledException e) { return true; } } return true; }
static HighlightInfo checkUnreachableStatement(@Nullable PsiCodeBlock codeBlock) { if (codeBlock == null) return null; // do not compute constant expressions for if() statement condition // see JLS 14.20 Unreachable Statements try { AllVariablesControlFlowPolicy policy = AllVariablesControlFlowPolicy.getInstance(); final ControlFlow controlFlow = ControlFlowFactory.getInstance(codeBlock.getProject()) .getControlFlow(codeBlock, policy, false, false); final PsiElement unreachableStatement = ControlFlowUtil.getUnreachableStatement(controlFlow); if (unreachableStatement != null) { String description = JavaErrorMessages.message("unreachable.statement"); return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(unreachableStatement) .descriptionAndTooltip(description) .create(); } } catch (AnalysisCanceledException | IndexNotReadyException e) { // incomplete code } return null; }
@Override public void onReferencesBuild(RefElement refElement) { if (refElement instanceof RefClass) { final PsiClass psiClass = (PsiClass) refElement.getElement(); if (psiClass != null) { if (refElement.isEntry()) { ((RefClassImpl) refElement).setFlag(false, CAN_BE_FINAL_MASK); } PsiMethod[] psiMethods = psiClass.getMethods(); PsiField[] psiFields = psiClass.getFields(); HashSet<PsiVariable> allFields = new HashSet<PsiVariable>(); ContainerUtil.addAll(allFields, psiFields); ArrayList<PsiVariable> instanceInitializerInitializedFields = new ArrayList<PsiVariable>(); boolean hasInitializers = false; for (PsiClassInitializer initializer : psiClass.getInitializers()) { PsiCodeBlock body = initializer.getBody(); hasInitializers = true; ControlFlow flow; try { flow = ControlFlowFactory.getInstance(body.getProject()) .getControlFlow( body, LocalsOrMyInstanceFieldsControlFlowPolicy.getInstance(), false); } catch (AnalysisCanceledException e) { flow = ControlFlow.EMPTY; } Collection<PsiVariable> writtenVariables = new ArrayList<PsiVariable>(); ControlFlowUtil.getWrittenVariables(flow, 0, flow.getSize(), false, writtenVariables); for (PsiVariable psiVariable : writtenVariables) { if (allFields.contains(psiVariable)) { if (instanceInitializerInitializedFields.contains(psiVariable)) { allFields.remove(psiVariable); instanceInitializerInitializedFields.remove(psiVariable); } else { instanceInitializerInitializedFields.add(psiVariable); } } } for (PsiVariable psiVariable : writtenVariables) { if (!instanceInitializerInitializedFields.contains(psiVariable)) { allFields.remove(psiVariable); } } } for (PsiMethod psiMethod : psiMethods) { if (psiMethod.isConstructor()) { PsiCodeBlock body = psiMethod.getBody(); if (body != null) { hasInitializers = true; ControlFlow flow; try { flow = ControlFlowFactory.getInstance(body.getProject()) .getControlFlow( body, LocalsOrMyInstanceFieldsControlFlowPolicy.getInstance(), false); } catch (AnalysisCanceledException e) { flow = ControlFlow.EMPTY; } Collection<PsiVariable> writtenVariables = ControlFlowUtil.getWrittenVariables(flow, 0, flow.getSize(), false); for (PsiVariable psiVariable : writtenVariables) { if (instanceInitializerInitializedFields.contains(psiVariable)) { allFields.remove(psiVariable); instanceInitializerInitializedFields.remove(psiVariable); } } List<PsiMethod> redirectedConstructors = HighlightControlFlowUtil.getChainedConstructors(psiMethod); if (redirectedConstructors == null || redirectedConstructors.isEmpty()) { List<PsiVariable> ssaVariables = ControlFlowUtil.getSSAVariables(flow); ArrayList<PsiVariable> good = new ArrayList<PsiVariable>(ssaVariables); good.addAll(instanceInitializerInitializedFields); allFields.retainAll(good); } else { allFields.removeAll(writtenVariables); } } } } for (PsiField psiField : psiFields) { if ((!hasInitializers || !allFields.contains(psiField)) && psiField.getInitializer() == null) { final RefFieldImpl refField = (RefFieldImpl) myManager.getReference(psiField); if (refField != null) { refField.setFlag(false, CAN_BE_FINAL_MASK); } } } } } else if (refElement instanceof RefMethod) { final RefMethod refMethod = (RefMethod) refElement; if (refMethod.isEntry()) { ((RefMethodImpl) refMethod).setFlag(false, CAN_BE_FINAL_MASK); } } }