/** * @param sideEffects if null, delete usages, otherwise collect side effects * @return true if there are at least one unrecoverable side effect found, false if no side * effects, null if read usage found (may happen if interval between fix creation in invoke() * call was long enough) * @throws com.intellij.util.IncorrectOperationException */ static Boolean processUsage( PsiElement element, PsiVariable variable, List<PsiElement> sideEffects, int deleteMode) throws IncorrectOperationException { if (!element.isValid()) return null; PsiElementFactory factory = JavaPsiFacade.getInstance(variable.getProject()).getElementFactory(); while (element != null) { if (element instanceof PsiAssignmentExpression) { PsiAssignmentExpression expression = (PsiAssignmentExpression) element; PsiExpression lExpression = expression.getLExpression(); // there should not be read access to the variable, otherwise it is not unused if (!(lExpression instanceof PsiReferenceExpression) || variable != ((PsiReferenceExpression) lExpression).resolve()) { return null; } PsiExpression rExpression = expression.getRExpression(); rExpression = PsiUtil.deparenthesizeExpression(rExpression); if (rExpression == null) return true; // replace assignment with expression and resimplify boolean sideEffectFound = checkSideEffects(rExpression, variable, sideEffects); if (!(element.getParent() instanceof PsiExpressionStatement) || PsiUtil.isStatement(rExpression)) { if (deleteMode == MAKE_STATEMENT || deleteMode == DELETE_ALL && !(element.getParent() instanceof PsiExpressionStatement)) { element = replaceElementWithExpression(rExpression, factory, element); while (element.getParent() instanceof PsiParenthesizedExpression) { element = element.getParent().replace(element); } List<PsiElement> references = new ArrayList<PsiElement>(); collectReferences(element, variable, references); deleteReferences(variable, references, deleteMode); } else if (deleteMode == DELETE_ALL) { deleteWholeStatement(element, factory); } return true; } else { if (deleteMode != CANCEL) { deleteWholeStatement(element, factory); } return !sideEffectFound; } } else if (element instanceof PsiExpressionStatement && deleteMode != CANCEL) { final PsiElement parent = element.getParent(); if (parent instanceof PsiIfStatement || parent instanceof PsiLoopStatement && ((PsiLoopStatement) parent).getBody() == element) { element.replace( JavaPsiFacade.getElementFactory(element.getProject()) .createStatementFromText(";", element)); } else { element.delete(); } break; } else if (element instanceof PsiVariable && element == variable) { PsiExpression expression = variable.getInitializer(); if (expression != null) { expression = PsiUtil.deparenthesizeExpression(expression); } boolean sideEffectsFound = checkSideEffects(expression, variable, sideEffects); if (expression != null && PsiUtil.isStatement(expression) && variable instanceof PsiLocalVariable && !(variable.getParent() instanceof PsiDeclarationStatement && ((PsiDeclarationStatement) variable.getParent()).getDeclaredElements().length > 1)) { if (deleteMode == MAKE_STATEMENT) { element = element.replace(createStatementIfNeeded(expression, factory, element)); List<PsiElement> references = new ArrayList<PsiElement>(); collectReferences(element, variable, references); deleteReferences(variable, references, deleteMode); } else if (deleteMode == DELETE_ALL) { element.delete(); } return true; } else { if (deleteMode != CANCEL) { if (element instanceof PsiField) { ((PsiField) element).normalizeDeclaration(); } element.delete(); } return !sideEffectsFound; } } element = element.getParent(); } return true; }
private void addTypesByVariable( HashSet<PsiType> typesSet, PsiVariable var, PsiFile scopeFile, HashSet<PsiVariable> checkedVariables, int flags, TextRange rangeToIgnore) { if (!checkedVariables.add(var)) return; // System.out.println("analyzing usages of " + var + " in file " + scopeFile); SearchScope searchScope = new LocalSearchScope(scopeFile); if (BitUtil.isSet(flags, CHECK_USAGE) || BitUtil.isSet(flags, CHECK_DOWN)) { for (PsiReference varRef : ReferencesSearch.search(var, searchScope, false)) { PsiElement ref = varRef.getElement(); if (BitUtil.isSet(flags, CHECK_USAGE)) { PsiType type = guessElementTypeFromReference(myMethodPatternMap, ref, rangeToIgnore); if (type != null && !(type instanceof PsiPrimitiveType)) { typesSet.add(type); } } if (BitUtil.isSet(flags, CHECK_DOWN)) { if (ref.getParent() instanceof PsiExpressionList && ref.getParent().getParent() instanceof PsiMethodCallExpression) { // TODO : new PsiExpressionList list = (PsiExpressionList) ref.getParent(); PsiExpression[] args = list.getExpressions(); int argIndex = -1; for (int j = 0; j < args.length; j++) { PsiExpression arg = args[j]; if (arg.equals(ref)) { argIndex = j; break; } } PsiMethodCallExpression methodCall = (PsiMethodCallExpression) list.getParent(); PsiMethod method = (PsiMethod) methodCall.getMethodExpression().resolve(); if (method != null) { PsiParameter[] parameters = method.getParameterList().getParameters(); if (argIndex < parameters.length) { addTypesByVariable( typesSet, parameters[argIndex], method.getContainingFile(), checkedVariables, flags | CHECK_USAGE, rangeToIgnore); } } } } } } if (BitUtil.isSet(flags, CHECK_UP)) { if (var instanceof PsiParameter && var.getParent() instanceof PsiParameterList && var.getParent().getParent() instanceof PsiMethod) { PsiParameterList list = (PsiParameterList) var.getParent(); PsiParameter[] parameters = list.getParameters(); int argIndex = -1; for (int i = 0; i < parameters.length; i++) { PsiParameter parameter = parameters[i]; if (parameter.equals(var)) { argIndex = i; break; } } PsiMethod method = (PsiMethod) var.getParent().getParent(); // System.out.println("analyzing usages of " + method + " in file " + scopeFile); for (PsiReference methodRef : ReferencesSearch.search(method, searchScope, false)) { PsiElement ref = methodRef.getElement(); if (ref.getParent() instanceof PsiMethodCallExpression) { PsiMethodCallExpression methodCall = (PsiMethodCallExpression) ref.getParent(); PsiExpression[] args = methodCall.getArgumentList().getExpressions(); if (args.length <= argIndex) continue; PsiExpression arg = args[argIndex]; if (arg instanceof PsiReferenceExpression) { PsiElement refElement = ((PsiReferenceExpression) arg).resolve(); if (refElement instanceof PsiVariable) { addTypesByVariable( typesSet, (PsiVariable) refElement, scopeFile, checkedVariables, flags | CHECK_USAGE, rangeToIgnore); } } // TODO : constructor } } } } }