public void removeParametersUsedInExitsOnly(PsiElement codeFragment, Collection<PsiStatement> exitStatements, ControlFlow controlFlow, int startOffset, int endOffset) { final LocalSearchScope scope = new LocalSearchScope(codeFragment); Variables: for (Iterator<VariableData> iterator = myInputVariables.iterator(); iterator.hasNext();) { final VariableData data = iterator.next(); for (PsiReference ref : ReferencesSearch.search(data.variable, scope)) { PsiElement element = ref.getElement(); int elementOffset = controlFlow.getStartOffset(element); if (elementOffset >= startOffset && elementOffset <= endOffset) { if (!isInExitStatements(element, exitStatements)) continue Variables; } } iterator.remove(); } }
private static boolean blockCompletesAbruptly(@NotNull final PsiCodeBlock finallyBlock) { try { ControlFlow flow = ControlFlowFactory.getInstance(finallyBlock.getProject()).getControlFlow(finallyBlock, LocalsOrMyInstanceFieldsControlFlowPolicy.getInstance(), false); int completionReasons = ControlFlowUtil.getCompletionReasons(flow, 0, flow.getSize()); if(!BitUtil.isSet(completionReasons, ControlFlowUtil.NORMAL_COMPLETION_REASON)) { return true; } } catch(AnalysisCanceledException e) { return true; } return false; }
@NotNull private static Collection<ControlFlowUtil.VariableInfo> getFinalVariableProblemsInBlock(@NotNull Map<PsiElement, Collection<ControlFlowUtil.VariableInfo>> finalVarProblems, @NotNull PsiElement codeBlock) { Collection<ControlFlowUtil.VariableInfo> codeBlockProblems = finalVarProblems.get(codeBlock); if(codeBlockProblems == null) { try { final ControlFlow controlFlow = getControlFlowNoConstantEvaluate(codeBlock); codeBlockProblems = ControlFlowUtil.getInitializedTwice(controlFlow); } catch(AnalysisCanceledException e) { codeBlockProblems = Collections.emptyList(); } finalVarProblems.put(codeBlock, codeBlockProblems); } return codeBlockProblems; }
@Nullable static HighlightInfo checkInitializerCompleteNormally(@NotNull PsiClassInitializer initializer) { final PsiCodeBlock body = initializer.getBody(); // unhandled exceptions already reported try { final ControlFlow controlFlow = getControlFlowNoConstantEvaluate(body); final int completionReasons = ControlFlowUtil.getCompletionReasons(controlFlow, 0, controlFlow.getSize()); if((completionReasons & ControlFlowUtil.NORMAL_COMPLETION_REASON) == 0) { String description = JavaErrorMessages.message("initializer.must.be.able.to.complete.normally"); return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(body).descriptionAndTooltip(description).create(); } } catch(AnalysisCanceledException e) { // incomplete code } return null; }
public void removeParametersUsedInExitsOnly(PsiElement codeFragment, Collection<PsiStatement> exitStatements, ControlFlow controlFlow, int startOffset, int endOffset) { final LocalSearchScope scope = new LocalSearchScope(codeFragment); Variables: for(Iterator<VariableData> iterator = myInputVariables.iterator(); iterator.hasNext(); ) { final VariableData data = iterator.next(); for(PsiReference ref : ReferencesSearch.search(data.variable, scope)) { PsiElement element = ref.getElement(); int elementOffset = controlFlow.getStartOffset(element); if(elementOffset >= startOffset && elementOffset <= endOffset) { if(!isInExitStatements(element, exitStatements)) { continue Variables; } } } iterator.remove(); } }
private boolean isValueCompatibleNoCache() { final PsiElement body = getBody(); if(body instanceof PsiCodeBlock) { try { ControlFlow controlFlow = ControlFlowFactory.getInstance(getProject()).getControlFlow(body, ourPolicy, false, false); int startOffset = controlFlow.getStartOffset(body); int endOffset = controlFlow.getEndOffset(body); if(startOffset != -1 && endOffset != -1 && ControlFlowUtil.canCompleteNormally(controlFlow, startOffset, endOffset)) { return false; } } //error would be shown inside body catch(AnalysisCanceledException ignore) { } for(PsiReturnStatement statement : PsiUtil.findReturnStatements((PsiCodeBlock) body)) { if(statement.getReturnValue() == null) { return false; } } } return true; }
@Nullable static HighlightInfo checkMissingReturnStatement(@Nullable PsiCodeBlock body, @Nullable PsiType returnType) { if(body == null || returnType == null || PsiType.VOID.equals(returnType.getDeepComponentType())) { return null; } // do not compute constant expressions for if() statement condition // see JLS 14.20 Unreachable Statements try { ControlFlow controlFlow = getControlFlowNoConstantEvaluate(body); if(!ControlFlowUtil.returnPresent(controlFlow)) { PsiJavaToken rBrace = body.getRBrace(); PsiElement context = rBrace == null ? body.getLastChild() : rBrace; String message = JavaErrorMessages.message("missing.return.statement"); HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(context).descriptionAndTooltip(message).create(); PsiElement parent = body.getParent(); if(parent instanceof PsiMethod) { PsiMethod method = (PsiMethod) parent; QuickFixAction.registerQuickFixAction(info, QUICK_FIX_FACTORY.createAddReturnFix(method)); QuickFixAction.registerQuickFixAction(info, QUICK_FIX_FACTORY.createMethodReturnFix(method, PsiType.VOID, true)); } return info; } } catch(AnalysisCanceledException ignored) { } return null; }
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 e) { // incomplete code } catch(IndexNotReadyException ignored) { } return null; }
/** * see JLS chapter 16 * * @return true if variable assigned (maybe more than once) */ private static boolean variableDefinitelyAssignedIn(@NotNull PsiVariable variable, @NotNull PsiElement context) { try { ControlFlow controlFlow = getControlFlow(context); return ControlFlowUtil.isVariableDefinitelyAssigned(variable, controlFlow); } catch(AnalysisCanceledException e) { return false; } }
private static boolean variableDefinitelyNotAssignedIn(@NotNull PsiVariable variable, @NotNull PsiElement context) { try { ControlFlow controlFlow = getControlFlow(context); return ControlFlowUtil.isVariableDefinitelyNotAssigned(variable, controlFlow); } catch(AnalysisCanceledException e) { return false; } }
private void declareLocalVariables() throws IncorrectOperationException { final PsiElement codeFragment = ControlFlowUtil.findCodeFragment(getMatchStart()); try { final Project project = getMatchStart().getProject(); final ControlFlow controlFlow = ControlFlowFactory.getInstance(project) .getControlFlow(codeFragment, new LocalsControlFlowPolicy(codeFragment)); final int endOffset = controlFlow.getEndOffset(getMatchEnd()); final int startOffset = controlFlow.getStartOffset(getMatchStart()); final List<PsiVariable> usedVariables = ControlFlowUtil.getUsedVariables(controlFlow, endOffset, controlFlow.getSize()); Collection<ControlFlowUtil.VariableInfo> reassigned = ControlFlowUtil.getInitializedTwice(controlFlow, endOffset, controlFlow.getSize()); final Collection<PsiVariable> outVariables = ControlFlowUtil.getWrittenVariables(controlFlow, startOffset, endOffset, false); for (PsiVariable variable : usedVariables) { if (!outVariables.contains(variable)) { final PsiIdentifier identifier = variable.getNameIdentifier(); if (identifier != null) { final TextRange textRange = checkRange(identifier); final TextRange startRange = checkRange(getMatchStart()); final TextRange endRange = checkRange(getMatchEnd()); if (textRange.getStartOffset() >= startRange.getStartOffset() && textRange.getEndOffset() <= endRange.getEndOffset()) { final String name = variable.getName(); LOG.assertTrue(name != null); PsiDeclarationStatement statement = JavaPsiFacade.getInstance(project).getElementFactory().createVariableDeclarationStatement(name, variable.getType(), null); if (reassigned.contains(new ControlFlowUtil.VariableInfo(variable, null))) { final PsiElement[] psiElements = statement.getDeclaredElements(); final PsiModifierList modifierList = ((PsiVariable)psiElements[0]).getModifierList(); LOG.assertTrue(modifierList != null); modifierList.setModifierProperty(PsiModifier.FINAL, false); } getMatchStart().getParent().addBefore(statement, getMatchStart()); } } } } } catch (AnalysisCanceledException e) { //skip match } }
private void highlightExitPoints(final PsiStatement parent, final PsiCodeBlock body) throws AnalysisCanceledException { final Project project = myTarget.getProject(); ControlFlow flow = ControlFlowFactory.getInstance(project).getControlFlow(body, LocalsOrMyInstanceFieldsControlFlowPolicy.getInstance(), false); Collection<PsiStatement> exitStatements = ControlFlowUtil.findExitPointsAndStatements(flow, 0, flow.getSize(), new IntArrayList(), PsiReturnStatement.class, PsiBreakStatement.class, PsiContinueStatement.class, PsiThrowStatement.class); if(!exitStatements.contains(parent)) { return; } PsiElement originalTarget = getExitTarget(parent); final Iterator<PsiStatement> it = exitStatements.iterator(); while(it.hasNext()) { PsiStatement psiStatement = it.next(); if(getExitTarget(psiStatement) != originalTarget) { it.remove(); } } for(PsiElement e : exitStatements) { addOccurrence(e); } myStatusText = CodeInsightBundle.message("status.bar.exit.points.highlighted.message", exitStatements.size(), HighlightUsagesHandler.getShortcutText()); }
private static void doTestFor(final File file) throws Exception { String contents = StringUtil.convertLineSeparators(FileUtil.loadFile(file)); configureFromFileText(file.getName(), contents); // extract factory policy class name Pattern pattern = Pattern.compile("^// (\\S*).*", Pattern.DOTALL); Matcher matcher = pattern.matcher(contents); assertTrue(matcher.matches()); final String policyClassName = matcher.group(1); final ControlFlowPolicy policy; if ("LocalsOrMyInstanceFieldsControlFlowPolicy".equals(policyClassName)) { policy = LocalsOrMyInstanceFieldsControlFlowPolicy.getInstance(); } else { policy = null; } final int offset = getEditor().getCaretModel().getOffset(); PsiElement element = getFile().findElementAt(offset); element = PsiTreeUtil.getParentOfType(element, PsiCodeBlock.class, false); assertTrue("Selected element: "+element, element instanceof PsiCodeBlock); ControlFlow controlFlow = ControlFlowFactory.getInstance(getProject()).getControlFlow(element, policy); String result = controlFlow.toString().trim(); final String expectedFullPath = StringUtil.trimEnd(file.getPath(),".java") + ".txt"; VirtualFile expectedFile = LocalFileSystem.getInstance().findFileByPath(expectedFullPath); String expected = new String(expectedFile.contentsToByteArray()).trim(); expected = expected.replaceAll("\r",""); assertEquals("Text mismatch (in file "+expectedFullPath+"):\n",expected, result); }
public void testMethodWithOnlyDoWhileStatementHasExitPoints() throws Exception { configureFromFileText("a.java", "public class Foo {\n" + " public void foo() {\n" + " boolean f;\n" + " do {\n" + " f = something();\n" + " } while (f);\n" + " }\n" + "}"); final PsiCodeBlock body = ((PsiJavaFile)getFile()).getClasses()[0].getMethods()[0].getBody(); ControlFlow flow = ControlFlowFactory.getInstance(getProject()).getControlFlow(body, new LocalsControlFlowPolicy(body), false); IntArrayList exitPoints = new IntArrayList(); ControlFlowUtil.findExitPointsAndStatements(flow, 0, flow.getSize() -1 , exitPoints, ControlFlowUtil.DEFAULT_EXIT_STATEMENTS_CLASSES); assertEquals(1, exitPoints.size()); }
@NotNull private static List<PsiClassType> getTryExceptions(@NotNull PsiTryStatement tryStatement) { List<PsiClassType> array = ContainerUtil.newArrayList(); PsiResourceList resourceList = tryStatement.getResourceList(); if(resourceList != null) { for(PsiResourceListElement resource : resourceList) { addExceptions(array, getUnhandledCloserExceptions(resource, resourceList)); } } PsiCodeBlock tryBlock = tryStatement.getTryBlock(); if(tryBlock != null) { addExceptions(array, getThrownExceptions(tryBlock)); } for(PsiParameter parameter : tryStatement.getCatchBlockParameters()) { PsiType exception = parameter.getType(); for(int j = array.size() - 1; j >= 0; j--) { PsiClassType exception1 = array.get(j); if(exception.isAssignableFrom(exception1)) { array.remove(exception1); } } } for(PsiCodeBlock catchBlock : tryStatement.getCatchBlocks()) { addExceptions(array, getThrownExceptions(catchBlock)); } PsiCodeBlock finallyBlock = tryStatement.getFinallyBlock(); if(finallyBlock != null) { // if finally block completes normally, exception not caught // if finally block completes abruptly, exception gets lost try { ControlFlow flow = ControlFlowFactory.getInstance(finallyBlock.getProject()).getControlFlow(finallyBlock, LocalsOrMyInstanceFieldsControlFlowPolicy.getInstance(), false); int completionReasons = ControlFlowUtil.getCompletionReasons(flow, 0, flow.getSize()); List<PsiClassType> thrownExceptions = getThrownExceptions(finallyBlock); if(!BitUtil.isSet(completionReasons, ControlFlowUtil.NORMAL_COMPLETION_REASON)) { array = ContainerUtil.newArrayList(thrownExceptions); } else { addExceptions(array, thrownExceptions); } } catch(AnalysisCanceledException e) { // incomplete code } } return array; }
@NotNull public static ControlFlow getControlFlowNoConstantEvaluate(@NotNull PsiElement body) throws AnalysisCanceledException { LocalsOrMyInstanceFieldsControlFlowPolicy policy = LocalsOrMyInstanceFieldsControlFlowPolicy.getInstance(); return ControlFlowFactory.getInstance(body.getProject()).getControlFlow(body, policy, false, false); }
@NotNull private static ControlFlow getControlFlow(@NotNull PsiElement context) throws AnalysisCanceledException { LocalsOrMyInstanceFieldsControlFlowPolicy policy = LocalsOrMyInstanceFieldsControlFlowPolicy.getInstance(); return ControlFlowFactory.getInstance(context.getProject()).getControlFlow(context, policy); }
public static boolean isEffectivelyFinal(@NotNull PsiVariable variable, @NotNull PsiElement scope, @Nullable PsiJavaCodeReferenceElement context) { boolean effectivelyFinal; if(variable instanceof PsiParameter) { effectivelyFinal = notAccessedForWriting(variable, new LocalSearchScope(((PsiParameter) variable).getDeclarationScope())); } else { final ControlFlow controlFlow; try { PsiElement codeBlock = PsiUtil.getVariableCodeBlock(variable, context); if(codeBlock == null) { return true; } controlFlow = getControlFlow(codeBlock); } catch(AnalysisCanceledException e) { return true; } final List<PsiReferenceExpression> readBeforeWriteLocals = ControlFlowUtil.getReadBeforeWriteLocals(controlFlow); for(PsiReferenceExpression expression : readBeforeWriteLocals) { if(expression.resolve() == variable) { return PsiUtil.isAccessedForReading(expression); } } final Collection<ControlFlowUtil.VariableInfo> initializedTwice = ControlFlowUtil.getInitializedTwice(controlFlow); effectivelyFinal = !initializedTwice.contains(new ControlFlowUtil.VariableInfo(variable, null)); if(effectivelyFinal) { effectivelyFinal = notAccessedForWriting(variable, new LocalSearchScope(scope)); } } return effectivelyFinal; }
public DuplicatesFinder(PsiElement[] pattern, InputVariables parameters, @Nullable ReturnValue returnValue, @NotNull List<? extends PsiVariable> outputParameters) { myReturnValue = returnValue; LOG.assertTrue(pattern.length > 0); myPattern = pattern; myPatternAsList = Arrays.asList(myPattern); myParameters = parameters; myOutputParameters = outputParameters; final PsiElement codeFragment = ControlFlowUtil.findCodeFragment(pattern[0]); try { final ControlFlow controlFlow = ControlFlowFactory.getInstance(codeFragment.getProject()).getControlFlow(codeFragment, new LocalsControlFlowPolicy(codeFragment), false); int startOffset; int i = 0; do { startOffset = controlFlow.getStartOffset(pattern[i++]); } while(startOffset < 0 && i < pattern.length); int endOffset; int j = pattern.length - 1; do { endOffset = controlFlow.getEndOffset(pattern[j--]); } while(endOffset < 0 && j >= 0); IntArrayList exitPoints = new IntArrayList(); final Collection<PsiStatement> exitStatements = ControlFlowUtil.findExitPointsAndStatements(controlFlow, startOffset, endOffset, exitPoints, ControlFlowUtil.DEFAULT_EXIT_STATEMENTS_CLASSES); myMultipleExitPoints = exitPoints.size() > 1; if(myMultipleExitPoints) { myParameters.removeParametersUsedInExitsOnly(codeFragment, exitStatements, controlFlow, startOffset, endOffset); } } catch(AnalysisCanceledException e) { } }
private boolean checkPostVariableUsages(final ArrayList<PsiElement> candidates, final Match match) { final PsiElement codeFragment = ControlFlowUtil.findCodeFragment(candidates.get(0)); try { final ControlFlow controlFlow = ControlFlowFactory.getInstance(codeFragment.getProject()).getControlFlow(codeFragment, new LocalsControlFlowPolicy(codeFragment), false); int startOffset; int i = 0; do { startOffset = controlFlow.getStartOffset(candidates.get(i++)); } while(startOffset < 0 && i < candidates.size()); int endOffset; int j = candidates.size() - 1; do { endOffset = controlFlow.getEndOffset(candidates.get(j--)); } while(endOffset < 0 && j >= 0); final IntArrayList exitPoints = new IntArrayList(); ControlFlowUtil.findExitPointsAndStatements(controlFlow, startOffset, endOffset, exitPoints, ControlFlowUtil.DEFAULT_EXIT_STATEMENTS_CLASSES); final PsiVariable[] outVariables = ControlFlowUtil.getOutputVariables(controlFlow, startOffset, endOffset, exitPoints.toArray()); if(outVariables.length > 0) { if(outVariables.length == 1) { ReturnValue returnValue = match.getReturnValue(); if(returnValue == null) { returnValue = myReturnValue; } if(returnValue instanceof VariableReturnValue) { final ReturnValue value = match.getOutputVariableValue(((VariableReturnValue) returnValue).getVariable()); if(value != null) { if(value.isEquivalent(new VariableReturnValue(outVariables[0]))) { return false; } if(value instanceof ExpressionReturnValue) { final PsiExpression expression = ((ExpressionReturnValue) value).getExpression(); if(expression instanceof PsiReferenceExpression) { final PsiElement variable = ((PsiReferenceExpression) expression).resolve(); return variable == null || !PsiEquivalenceUtil.areElementsEquivalent(variable, outVariables[0]); } } } } } return true; } } catch(AnalysisCanceledException e) { } return false; }