Merge remote-tracking branch 'origin/master'

This commit is contained in:
Roman Shevchenko
2016-10-21 18:28:09 +02:00
177 changed files with 2310 additions and 1009 deletions
@@ -106,7 +106,7 @@ class AddModuleDependencyFix extends AddOrderEntryFix {
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
return !project.isDisposed() && !myCurrentModule.isDisposed() && myModules.stream().noneMatch(Module::isDisposed);
return !project.isDisposed() && !myCurrentModule.isDisposed() && !myModules.isEmpty() && myModules.stream().noneMatch(Module::isDisposed);
}
@Override
@@ -56,6 +56,7 @@ abstract class MigrateToStreamFix implements LocalQuickFix {
if (!FileModificationService.getInstance().preparePsiElementForWrite(loopStatement)) return;
PsiElement result = migrate(project, loopStatement, body, tb);
if(result != null) {
source.cleanUpSource();
simplifyAndFormat(project, result);
}
}
@@ -390,23 +390,14 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
return consumerClass != null ? psiFacade.getElementFactory().createType(consumerClass, variable.getType()) : null;
}
static boolean isVariableSuitableForStream(PsiVariable variable, PsiStatement statement) {
PsiElement declaration = variable.getParent();
// For-loop initializer is not effectively final, but suitable for stream conversion
if(declaration instanceof PsiDeclarationStatement) {
PsiElement grandParent = declaration.getParent();
if (grandParent instanceof PsiForStatement) {
PsiForStatement forStatement = (PsiForStatement)grandParent;
if (forStatement.getInitialization() == declaration) {
PsiStatement body = forStatement.getBody();
if(body != null && PsiTreeUtil.isAncestor(statement, body, false)) {
return ReferencesSearch.search(variable, new LocalSearchScope(body)).forEach(ref -> {
PsiElement element = ref.getElement();
return !(element instanceof PsiExpression) || !PsiUtil.isAccessedForWriting((PsiExpression)element);
});
}
}
}
static boolean isVariableSuitableForStream(PsiVariable variable, PsiStatement statement, TerminalBlock tb) {
if(ReferencesSearch.search(variable, variable.getUseScope()).forEach(ref -> {
PsiElement element = ref.getElement();
return !(element instanceof PsiExpression) ||
!PsiUtil.isAccessedForWriting((PsiExpression)element) ||
tb.operations().anyMatch(op -> op.isWriteAllowed(variable, (PsiExpression)element));
})) {
return true;
}
return HighlightControlFlowUtil.isEffectivelyFinal(variable, statement, null);
}
@@ -429,6 +420,58 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
return null;
}
/**
* Checks whether variable can be referenced between start and loop entry. Back-edges are also considered, so the actual place
* where it referenced might be outside of (start, loop entry) interval.
*
* @param flow ControlFlow to analyze
* @param start start point
* @param loop loop to check
* @param variable variable to analyze
* @return true if variable can be referenced between start and stop points
*/
private static boolean isVariableReferencedBeforeLoopEntry(final ControlFlow flow,
final int start,
final PsiLoopStatement loop,
final PsiVariable variable) {
final int loopStart = flow.getStartOffset(loop);
final int loopEnd = flow.getEndOffset(loop);
if(start == loopStart) return false;
List<ControlFlowUtil.ControlFlowEdge> edges = ControlFlowUtil.getEdges(flow, start);
// DFS visits instructions mainly in backward direction while here visiting in forward direction
// greatly reduces number of iterations.
Collections.reverse(edges);
BitSet referenced = new BitSet();
boolean changed = true;
while(changed) {
changed = false;
for(ControlFlowUtil.ControlFlowEdge edge: edges) {
int from = edge.myFrom;
int to = edge.myTo;
if(referenced.get(from)) {
// jump to the loop start from within the loop is not considered as loop entry
if(to == loopStart && (from < loopStart || from >= loopEnd)) {
return true;
}
if(!referenced.get(to)) {
referenced.set(to);
changed = true;
}
continue;
}
if(ControlFlowUtil.isVariableAccess(flow, from, variable)) {
referenced.set(from);
referenced.set(to);
if(to == loopStart) return true;
changed = true;
}
}
}
return false;
}
enum InitializerUsageStatus {
// Variable is declared just before the wanted place
DECLARED_JUST_BEFORE,
@@ -440,7 +483,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
UNKNOWN
}
static InitializerUsageStatus getInitializerUsageStatus(PsiVariable var, PsiStatement nextStatement) {
static InitializerUsageStatus getInitializerUsageStatus(PsiVariable var, PsiLoopStatement nextStatement) {
if(!(var instanceof PsiLocalVariable) || var.getInitializer() == null) return UNKNOWN;
if(isDeclarationJustBefore(var, nextStatement)) return DECLARED_JUST_BEFORE;
// Check that variable is declared in the same method or the same lambda expression
@@ -458,7 +501,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
}
int start = controlFlow.getEndOffset(var.getInitializer())+1;
int stop = controlFlow.getStartOffset(nextStatement);
if(ControlFlowUtil.isVariableReferencedBetween(controlFlow, start, stop, var)) return UNKNOWN;
if(isVariableReferencedBeforeLoopEntry(controlFlow, start, nextStatement, var)) return UNKNOWN;
if (!ControlFlowUtil.isValueUsedWithoutVisitingStop(controlFlow, start, stop, var)) return AT_WANTED_PLACE_ONLY;
return var.hasModifierProperty(PsiModifier.FINAL) ? UNKNOWN : AT_WANTED_PLACE;
}
@@ -494,6 +537,12 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
processLoop(statement);
}
@Override
public void visitWhileStatement(PsiWhileStatement statement) {
super.visitWhileStatement(statement);
processLoop(statement);
}
@Override
public void visitForStatement(PsiForStatement statement) {
super.visitForStatement(statement);
@@ -524,7 +573,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
int startOffset = controlFlow.getStartOffset(body);
int endOffset = controlFlow.getEndOffset(body);
final List<PsiVariable> nonFinalVariables = StreamEx.of(ControlFlowUtil.getUsedVariables(controlFlow, startOffset, endOffset))
.remove(variable -> isVariableSuitableForStream(variable, statement)).toList();
.remove(variable -> isVariableSuitableForStream(variable, statement, tb)).toList();
if (exitPoints.isEmpty()) {
if(getIncrementedVariable(tb, nonFinalVariables) != null) {
@@ -679,6 +728,12 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
PsiStatement initialization = ((PsiForStatement)statement).getInitialization();
LOG.assertTrue(initialization != null);
return initialization.getTextRange();
} else if(statement instanceof PsiWhileStatement) {
PsiJavaToken rParenth = ((PsiWhileStatement)statement).getRParenth();
if (wholeStatement && rParenth != null) {
return new TextRange(statement.getTextOffset(), rParenth.getTextOffset() + 1);
}
return statement.getFirstChild().getTextRange();
} else {
throw new IllegalStateException("Unexpected statement type: "+statement);
}
@@ -830,6 +885,10 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
}
abstract String createReplacement();
boolean isWriteAllowed(PsiVariable variable, PsiExpression reference) {
return false;
}
}
static class FilterOp extends Operation {
@@ -921,6 +980,11 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
PsiExpression expression = myType == null ? myExpression : RefactoringUtil.convertInitializerToNormalExpression(myExpression, myType);
return "." + operationName + "(" + LambdaUtil.createLambda(myVariable, expression) + ")";
}
@Override
boolean isWriteAllowed(PsiVariable variable, PsiExpression reference) {
return variable == myVariable && reference.getParent() == myExpression.getParent();
}
}
static class FlatMapOp extends Operation {
@@ -954,6 +1018,11 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
return mySource.createReplacement();
}
@Override
boolean isWriteAllowed(PsiVariable variable, PsiExpression reference) {
return mySource.isWriteAllowed(variable, reference);
}
boolean breaksMe(PsiBreakStatement statement) {
return statement.findExitedStatement() == myLoop;
}
@@ -964,6 +1033,9 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
super(null, expression, variable);
}
void cleanUpSource() {
}
@Contract("null -> null")
static StreamSource tryCreate(PsiLoopStatement statement) {
if(statement instanceof PsiForStatement) {
@@ -973,10 +1045,74 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
ArrayStream source = ArrayStream.from((PsiForeachStatement)statement);
return source == null ? CollectionStream.from((PsiForeachStatement)statement) : source;
}
if(statement instanceof PsiWhileStatement) {
return BufferedReaderLines.from((PsiWhileStatement)statement);
}
return null;
}
}
static class BufferedReaderLines extends StreamSource {
private BufferedReaderLines(PsiVariable variable, PsiExpression expression) {
super(variable, expression);
}
@Override
String createReplacement() {
return myExpression.getText()+".lines()";
}
@Override
void cleanUpSource() {
myVariable.delete();
}
@Override
boolean isWriteAllowed(PsiVariable variable, PsiExpression reference) {
return myVariable == variable && reference.getParent() == PsiTreeUtil.getParentOfType(myExpression, PsiAssignmentExpression.class);
}
@Nullable
public static BufferedReaderLines from(PsiWhileStatement whileLoop) {
// while ((line = br.readLine()) != null)
PsiExpression condition = PsiUtil.skipParenthesizedExprDown(whileLoop.getCondition());
if(!(condition instanceof PsiBinaryExpression)) return null;
PsiBinaryExpression binOp = (PsiBinaryExpression)condition;
if(!JavaTokenType.NE.equals(binOp.getOperationTokenType())) return null;
PsiExpression operand = null;
if(ExpressionUtils.isNullLiteral(binOp.getROperand())) {
operand = binOp.getLOperand();
} else if(ExpressionUtils.isNullLiteral(binOp.getLOperand())) {
operand = binOp.getROperand();
}
if(operand == null) return null;
PsiAssignmentExpression assignment = ExpressionUtils.getAssignment(PsiUtil.skipParenthesizedExprDown(operand));
if(assignment == null) return null;
PsiExpression lValue = assignment.getLExpression();
if(!(lValue instanceof PsiReferenceExpression)) return null;
PsiElement element = ((PsiReferenceExpression)lValue).resolve();
if(!(element instanceof PsiLocalVariable)) return null;
PsiLocalVariable var = (PsiLocalVariable)element;
if(!ReferencesSearch.search(var, var.getUseScope()).forEach(ref -> {
return PsiTreeUtil.isAncestor(whileLoop, ref.getElement(), true);
})) {
return null;
}
PsiExpression rValue = PsiUtil.skipParenthesizedExprDown(assignment.getRExpression());
if(!(rValue instanceof PsiMethodCallExpression)) return null;
PsiMethodCallExpression call = (PsiMethodCallExpression)rValue;
if(call.getArgumentList().getExpressions().length != 0) return null;
if(!"readLine".equals(call.getMethodExpression().getReferenceName())) return null;
PsiExpression readerExpression = call.getMethodExpression().getQualifierExpression();
if(readerExpression == null) return null;
PsiMethod method = call.resolveMethod();
if(method == null) return null;
PsiClass aClass = method.getContainingClass();
if(aClass == null || !"java.io.BufferedReader".equals(aClass.getQualifiedName())) return null;
return new BufferedReaderLines(var, readerExpression);
}
}
static class ArrayStream extends StreamSource {
private ArrayStream(PsiVariable variable, PsiExpression expression) {
super(variable, expression);
@@ -1063,6 +1199,17 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
return className+"."+methodName+"("+myExpression.getText()+", "+myBound.getText()+")";
}
@Override
boolean isWriteAllowed(PsiVariable variable, PsiExpression reference) {
if(variable == myVariable) {
PsiForStatement forStatement = PsiTreeUtil.getParentOfType(variable, PsiForStatement.class);
if(forStatement != null) {
return PsiTreeUtil.isAncestor(forStatement.getUpdate(), reference, false);
}
}
return false;
}
@Nullable
public static CountingLoop from(PsiForStatement forStatement) {
// check that initialization is for(int/long i = <initial_value>;...;...)
@@ -1224,7 +1371,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
if(source == null || body == null) return null;
// flatMap from primitive to primitive is supported only if primitive types match
// otherwise it would be necessary to create bogus step like
// .mapToObj(var -> blahblah.stream()).flatMap(Function.identity())
// .mapToObj(var -> collection.stream()).flatMap(Function.identity())
if(myVariable.getType() instanceof PsiPrimitiveType && !myVariable.getType().equals(source.getVariable().getType())) return null;
FlatMapOp op = new FlatMapOp(myPreviousOp, source, myVariable, loopStatement);
TerminalBlock withFlatMap = new TerminalBlock(op, source.getVariable(), body);
@@ -1268,6 +1415,16 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
}
}
}
PsiAssignmentExpression assignment = ExpressionUtils.getAssignment(first);
if(assignment != null) {
PsiExpression lValue = assignment.getLExpression();
PsiExpression rValue = assignment.getRExpression();
if(rValue != null && lValue instanceof PsiReferenceExpression && ((PsiReferenceExpression)lValue).isReferenceTo(myVariable)) {
PsiStatement[] leftOver = Arrays.copyOfRange(myStatements, 1, myStatements.length);
MapOp op = new MapOp(myPreviousOp, rValue, myVariable, myVariable.getType());
return new TerminalBlock(op, myVariable, leftOver);
}
}
}
return null;
}
@@ -1300,7 +1457,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
}
@NotNull
private StreamEx<Operation> operations() {
StreamEx<Operation> operations() {
return StreamEx.iterate(myPreviousOp, Objects::nonNull, Operation::getPreviousOp);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -45,7 +45,9 @@ import com.intellij.refactoring.listeners.RefactoringEventData;
import com.intellij.refactoring.listeners.RefactoringEventListener;
import com.intellij.refactoring.util.CommonRefactoringUtil;
import com.intellij.refactoring.util.InlineUtil;
import com.intellij.util.*;
import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.Query;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -96,7 +98,7 @@ public class InlineLocalHandler extends JavaInlineActionHandler {
final PsiElement element = psiReference.getElement();
PsiElement innerClass = PsiTreeUtil.getParentOfType(element, PsiClass.class, PsiLambdaExpression.class);
while (innerClass != containingClass && innerClass != null) {
final PsiClass parentPsiClass = PsiTreeUtil.getParentOfType(innerClass, PsiClass.class, true);
final PsiElement parentPsiClass = PsiTreeUtil.getParentOfType(innerClass.getParent(), PsiClass.class, PsiLambdaExpression.class);
if (parentPsiClass == containingClass) {
if (innerClass instanceof PsiLambdaExpression) {
if (PsiTreeUtil.isAncestor(innerClass, local, false)) {
@@ -470,7 +470,6 @@ public class InlineMethodProcessor extends BaseRefactoringProcessor {
GenericInlineHandler.inlineReference(usage, myMethod, myInliners);
}
}
myMethod.delete();
}
else {
List<PsiReferenceExpression> refExprList = new ArrayList<>();
@@ -513,8 +512,8 @@ public class InlineMethodProcessor extends BaseRefactoringProcessor {
psiElement.delete();
}
}
if (myMethod.isWritable()) myMethod.delete();
}
if (myMethod.isWritable()) myMethod.delete();
}
removeAddedBracesWhenPossible();
}
@@ -544,8 +543,9 @@ public class InlineMethodProcessor extends BaseRefactoringProcessor {
}
public static void inlineConstructorCall(PsiCall constructorCall) {
final PsiMethod oldConstructor = constructorCall.resolveMethod();
PsiMethod oldConstructor = constructorCall.resolveMethod();
LOG.assertTrue(oldConstructor != null);
oldConstructor = (PsiMethod)oldConstructor.getNavigationElement();
PsiExpression[] instanceCreationArguments = constructorCall.getArgumentList().getExpressions();
if (oldConstructor.isVarArgs()) { //wrap with explicit array
final PsiParameter[] parameters = oldConstructor.getParameterList().getParameters();
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -81,6 +81,11 @@ public class InlineToAnonymousClassDialog extends InlineOptionsWithSearchSetting
protected void saveSearchInCommentsAndStrings(boolean searchInComments) {
JavaRefactoringSettings.getInstance().INLINE_CLASS_SEARCH_IN_COMMENTS = searchInComments;
}
@Override
protected boolean allowInlineAll() {
return true;
}
@Override
protected void saveSearchInTextOccurrences(boolean searchInTextOccurrences) {
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@ import com.intellij.openapi.util.Ref;
import com.intellij.patterns.ElementPattern;
import com.intellij.patterns.PlatformPatterns;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.searches.ClassInheritorsSearch;
import com.intellij.psi.search.searches.FunctionalExpressionSearch;
import com.intellij.psi.search.searches.ReferencesSearch;
@@ -115,7 +116,7 @@ public class InlineToAnonymousClassHandler extends JavaInlineActionHandler {
}
final Ref<String> errorMessage = new Ref<>();
if (!ProgressManager.getInstance().runProcessWithProgressSynchronously(() -> ApplicationManager.getApplication().runReadAction(() -> errorMessage.set(getCannotInlineMessage(psiClass))), "Check if inline is possible...", true, project)) return;
if (!ProgressManager.getInstance().runProcessWithProgressSynchronously(() -> ApplicationManager.getApplication().runReadAction(() -> errorMessage.set(getCannotInlineMessage((PsiClass)psiClass.getNavigationElement()))), "Check if inline is possible...", true, project)) return;
if (errorMessage.get() != null) {
CommonRefactoringUtil.showErrorHint(project, editor, errorMessage.get(), RefactoringBundle.message("inline.to.anonymous.refactoring"), null);
return;
@@ -201,7 +202,7 @@ public class InlineToAnonymousClassHandler extends JavaInlineActionHandler {
if (psiClass.hasModifierProperty(PsiModifier.ABSTRACT)) {
return RefactoringBundle.message("inline.to.anonymous.no.abstract");
}
if (!psiClass.getManager().isInProject(psiClass)) {
if (psiClass instanceof PsiCompiledElement) {
return "Library classes cannot be inlined";
}
@@ -230,6 +231,7 @@ public class InlineToAnonymousClassHandler extends JavaInlineActionHandler {
}
}
final GlobalSearchScope searchScope = GlobalSearchScope.projectScope(psiClass.getProject());
final PsiMethod[] methods = psiClass.getMethods();
for(PsiMethod method: methods) {
if (method.isConstructor()) {
@@ -238,7 +240,7 @@ public class InlineToAnonymousClassHandler extends JavaInlineActionHandler {
}
}
else if (method.findSuperMethods().length == 0) {
if (!ReferencesSearch.search(method).forEach(new AllowedUsagesProcessor(psiClass))) {
if (!ReferencesSearch.search(method, searchScope).forEach(new AllowedUsagesProcessor(psiClass))) {
return "Class cannot be inlined because there are usages of its methods not inherited from its superclass or interface";
}
}
@@ -253,7 +255,7 @@ public class InlineToAnonymousClassHandler extends JavaInlineActionHandler {
if (classModifiers.hasModifierProperty(PsiModifier.STATIC)) {
return "Class cannot be inlined because it has static inner classes";
}
if (!ReferencesSearch.search(innerClass).forEach(new AllowedUsagesProcessor(psiClass))) {
if (!ReferencesSearch.search(innerClass, searchScope).forEach(new AllowedUsagesProcessor(psiClass))) {
return "Class cannot be inlined because it has usages of its inner classes";
}
}
@@ -274,7 +276,7 @@ public class InlineToAnonymousClassHandler extends JavaInlineActionHandler {
return "Class cannot be inlined because it has static fields with non-constant initializers";
}
}
if (!ReferencesSearch.search(field).forEach(new AllowedUsagesProcessor(psiClass))) {
if (!ReferencesSearch.search(field, searchScope).forEach(new AllowedUsagesProcessor(psiClass))) {
return "Class cannot be inlined because it has usages of fields not inherited from its superclass";
}
}
@@ -305,7 +307,7 @@ public class InlineToAnonymousClassHandler extends JavaInlineActionHandler {
@Nullable
private static String getCannotInlineDueToUsagesMessage(final PsiClass aClass) {
boolean hasUsages = false;
for(PsiReference reference : ReferencesSearch.search(aClass)) {
for(PsiReference reference : ReferencesSearch.search(aClass, GlobalSearchScope.projectScope(aClass.getProject()))) {
final PsiElement element = reference.getElement();
if (element == null) continue;
if (!PsiTreeUtil.isAncestor(aClass, element, false)) {
@@ -359,10 +361,10 @@ public class InlineToAnonymousClassHandler extends JavaInlineActionHandler {
@Override
public boolean process(final PsiReference psiReference) {
if (PsiTreeUtil.isAncestor(myPsiElement, psiReference.getElement(), false)) {
PsiElement element = psiReference.getElement();
if (element != null && PsiTreeUtil.isAncestor(myPsiElement, element.getNavigationElement(), false)) {
return true;
}
PsiElement element = psiReference.getElement();
if (element instanceof PsiReferenceExpression) {
PsiExpression qualifier = ((PsiReferenceExpression)element).getQualifierExpression();
while (qualifier instanceof PsiParenthesizedExpression) {
@@ -371,7 +373,7 @@ public class InlineToAnonymousClassHandler extends JavaInlineActionHandler {
if (qualifier instanceof PsiNewExpression) {
PsiNewExpression newExpr = (PsiNewExpression) qualifier;
PsiJavaCodeReferenceElement classRef = newExpr.getClassReference();
if (classRef != null && myPsiElement.equals(classRef.resolve())) {
if (classRef != null && myPsiElement.isEquivalentTo(classRef.resolve())) {
return true;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -76,7 +76,8 @@ public class InlineToAnonymousClassProcessor extends BaseRefactoringProcessor {
return new UsageInfo[] { new UsageInfo(myCallToInline) };
}
Set<UsageInfo> usages = new HashSet<>();
for (PsiReference reference : ReferencesSearch.search(myClass)) {
final GlobalSearchScope searchScope = GlobalSearchScope.projectScope(myProject);
for (PsiReference reference : ReferencesSearch.search(myClass, searchScope)) {
usages.add(new UsageInfo(reference.getElement()));
}
@@ -89,9 +90,8 @@ public class InlineToAnonymousClassProcessor extends BaseRefactoringProcessor {
}
if (mySearchInNonJavaFiles) {
GlobalSearchScope projectScope = GlobalSearchScope.projectScope(myClass.getProject());
TextOccurrencesUtil.addTextOccurences(myClass, qName, projectScope, nonCodeUsages,
new NonCodeUsageInfoFactory(myClass, qName));
TextOccurrencesUtil.addTextOccurences(myClass, qName, searchScope, nonCodeUsages,
new NonCodeUsageInfoFactory(myClass, qName));
}
usages.addAll(nonCodeUsages);
}
@@ -99,6 +99,15 @@ public class InlineToAnonymousClassProcessor extends BaseRefactoringProcessor {
return usages.toArray(new UsageInfo[usages.size()]);
}
@NotNull
@Override
protected Collection<? extends PsiElement> getElementsToWrite(@NotNull UsageViewDescriptor descriptor) {
if (!myInlineThisOnly && !myClass.isWritable()) {
return Collections.emptyList();
}
return super.getElementsToWrite(descriptor);
}
protected void refreshElements(@NotNull PsiElement[] elements) {
assert elements.length == 1;
myClass = (PsiClass) elements [0];
@@ -156,7 +165,7 @@ public class InlineToAnonymousClassProcessor extends BaseRefactoringProcessor {
@Override
public void visitParameter(PsiParameter parameter) {
super.visitParameter(parameter);
if (PsiUtil.resolveClassInType(parameter.getType()) != myClass) return;
if (!myClass.isEquivalentTo(PsiUtil.resolveClassInType(parameter.getType()))) return;
for (PsiReference psiReference : ReferencesSearch.search(parameter)) {
final PsiElement refElement = psiReference.getElement();
@@ -180,7 +189,7 @@ public class InlineToAnonymousClassProcessor extends BaseRefactoringProcessor {
@Override
public void visitNewExpression(PsiNewExpression expression) {
super.visitNewExpression(expression);
if (PsiUtil.resolveClassInType(expression.getType()) != myClass) return;
if (!myClass.isEquivalentTo(PsiUtil.resolveClassInType(expression.getType()))) return;
result.putValue(expression, "Class cannot be inlined because a call to its constructor inside body");
}
@@ -189,7 +198,7 @@ public class InlineToAnonymousClassProcessor extends BaseRefactoringProcessor {
super.visitMethodCallExpression(expression);
final PsiReferenceExpression methodExpression = expression.getMethodExpression();
final PsiExpression qualifierExpression = methodExpression.getQualifierExpression();
if (qualifierExpression != null && PsiUtil.resolveClassInType(qualifierExpression.getType()) != myClass) return;
if (qualifierExpression != null && !myClass.isEquivalentTo(PsiUtil.resolveClassInType(qualifierExpression.getType()))) return;
final PsiElement resolved = methodExpression.resolve();
if (resolved instanceof PsiMethod) {
final PsiMethod method = (PsiMethod)resolved;
@@ -244,7 +253,7 @@ public class InlineToAnonymousClassProcessor extends BaseRefactoringProcessor {
LOG.error(e);
}
}
if (!myInlineThisOnly) {
if (!myInlineThisOnly && myClass.getOriginalElement().isWritable()) {
try {
myClass.delete();
}
@@ -262,7 +271,7 @@ public class InlineToAnonymousClassProcessor extends BaseRefactoringProcessor {
else {
PsiClass target = superType.resolve();
assert target != null : superType;
PsiElementFactory factory = JavaPsiFacade.getInstance(myClass.getProject()).getElementFactory();
PsiElementFactory factory = JavaPsiFacade.getInstance(myProject).getElementFactory();
PsiJavaCodeReferenceElement element = factory.createClassReferenceElement(target);
PsiJavaCodeReferenceElement reference = psiNewExpression.getClassReference();
assert reference != null : psiNewExpression;
@@ -275,11 +284,11 @@ public class InlineToAnonymousClassProcessor extends BaseRefactoringProcessor {
}
private void replaceWithSuperType(final PsiTypeElement typeElement, final PsiClassType superType) {
PsiElementFactory factory = JavaPsiFacade.getInstance(myClass.getProject()).getElementFactory();
PsiElementFactory factory = JavaPsiFacade.getInstance(myProject).getElementFactory();
PsiClassType psiType = (PsiClassType) typeElement.getType();
PsiClassType.ClassResolveResult classResolveResult = psiType.resolveGenerics();
PsiType substType = classResolveResult.getSubstitutor().substitute(superType);
assert classResolveResult.getElement() == myClass;
assert myClass.isEquivalentTo(classResolveResult.getElement());
try {
PsiElement replaced = typeElement.replace(factory.createTypeElement(substType));
JavaCodeStyleManager.getInstance(myProject).shortenClassReferences(replaced);
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -82,7 +82,8 @@ class InlineToAnonymousConstructorProcessor {
checkInlineChainingConstructor();
JavaResolveResult classResolveResult = myNewExpression.getClassReference().advancedResolve(false);
JavaResolveResult methodResolveResult = myNewExpression.resolveMethodGenerics();
myConstructor = (PsiMethod) methodResolveResult.getElement();
final PsiElement element = methodResolveResult.getElement();
myConstructor = element != null ? (PsiMethod) element.getNavigationElement() : null;
myConstructorArguments = myNewExpression.getArgumentList();
PsiSubstitutor classResolveSubstitutor = classResolveResult.getSubstitutor();
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -54,8 +54,6 @@ import com.intellij.psi.impl.source.jsp.jspJava.JspCodeBlock;
import com.intellij.psi.impl.source.jsp.jspJava.JspHolderMethod;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import com.intellij.psi.impl.source.tree.java.ReplaceExpressionUtil;
import com.intellij.psi.scope.processor.VariablesProcessor;
import com.intellij.psi.scope.util.PsiScopesUtil;
import com.intellij.psi.util.*;
import com.intellij.refactoring.*;
import com.intellij.refactoring.introduce.inplace.AbstractInplaceIntroducer;
@@ -755,14 +753,16 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase {
boolean skipForStatement = true;
final PsiForStatement forStatement = PsiTreeUtil.getParentOfType(expr, PsiForStatement.class);
if (forStatement != null) {
final VariablesProcessor variablesProcessor = new VariablesProcessor(false) {
@Override
protected boolean check(PsiVariable var, ResolveState state) {
return PsiTreeUtil.isAncestor(forStatement.getInitialization(), var, true);
}
};
PsiScopesUtil.treeWalkUp(variablesProcessor, expr, null);
skipForStatement = variablesProcessor.size() == 0;
Set<PsiVariable> vars = new HashSet<>();
SyntaxTraverser.psiTraverser().withRoot(expr)
.filter(element -> element instanceof PsiReferenceExpression)
.forEach(element -> {
final PsiElement resolve = ((PsiReferenceExpression)element).resolve();
if (resolve instanceof PsiVariable) {
vars.add((PsiVariable)resolve);
}
});
skipForStatement = vars.stream().noneMatch(variable -> PsiTreeUtil.isAncestor(forStatement.getInitialization(), variable, true));
}
PsiElement containerParent = tempContainer;
@@ -19,7 +19,7 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.ui.Messages;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiType;
import com.intellij.refactoring.typeMigration.usageInfo.OverridenUsageInfo;
import com.intellij.refactoring.typeMigration.usageInfo.OverriddenUsageInfo;
import com.intellij.util.ui.UIUtil;
import java.util.concurrent.atomic.AtomicReference;
@@ -34,7 +34,7 @@ class MigrateGetterNameSetting {
private final AtomicReference<Boolean> myGlobalValue = new AtomicReference<>();
void askUserIfNeed(final OverridenUsageInfo info, final String newMethodName, final PsiType migrationReturnType) {
void askUserIfNeed(final OverriddenUsageInfo info, final String newMethodName, final PsiType migrationReturnType) {
final Boolean globalValue = myGlobalValue.get();
if (globalValue == null) {
final String currentName = ((PsiMethod)info.getElement()).getName();
@@ -42,26 +42,23 @@ class MigrateGetterNameSetting {
currentName,
newMethodName,
migrationReturnType.getCanonicalText());
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
@Override
public void run() {
final Boolean globalValue = myGlobalValue.get();
if (globalValue == null) {
final int code = showChooserDialog(messageText);
if (code == 0) {
myGlobalValue.set(true);
info.setMigrateMethodName(newMethodName);
}
else if (code == 1) {
info.setMigrateMethodName(newMethodName);
}
else if (code == 2) {
myGlobalValue.set(false);
}
}
else if (globalValue.equals(Boolean.TRUE)) {
UIUtil.invokeAndWaitIfNeeded((Runnable)() -> {
final Boolean globalValue1 = myGlobalValue.get();
if (globalValue1 == null) {
final int code = showChooserDialog(messageText);
if (code == 0) {
myGlobalValue.set(true);
info.setMigrateMethodName(newMethodName);
}
else if (code == 1) {
info.setMigrateMethodName(newMethodName);
}
else if (code == 2) {
myGlobalValue.set(false);
}
}
else if (globalValue1.equals(Boolean.TRUE)) {
info.setMigrateMethodName(newMethodName);
}
});
}
@@ -46,15 +46,6 @@ public class TypeConversionDescriptorBase {
return null;
}
/**
* @return substitutor of converted method parameters
* or null if expression is not method call expression
*/
@Nullable
public PsiSubstitutor getConvertedMethodParameters() {
return null;
}
public PsiExpression replace(PsiExpression expression, @NotNull TypeEvaluator evaluator) throws IncorrectOperationException {
return expression;
}
@@ -348,14 +348,14 @@ public class TypeEvaluator {
}
public String getReport() {
final StringBuffer buffer = new StringBuffer();
final StringBuilder buffer = new StringBuilder();
final String[] t = new String[myTypeMap.size()];
int k = 0;
for (final TypeMigrationUsageInfo info : myTypeMap.keySet()) {
final LinkedList<PsiType> types = myTypeMap.get(info);
final StringBuffer b = new StringBuffer();
final StringBuilder b = new StringBuilder();
if (types != null) {
b.append(info.getElement()).append(" : ");
@@ -38,7 +38,7 @@ import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.refactoring.rename.RenameProcessor;
import com.intellij.refactoring.typeCook.deductive.PsiExtendedTypeVisitor;
import com.intellij.refactoring.typeMigration.usageInfo.OverridenUsageInfo;
import com.intellij.refactoring.typeMigration.usageInfo.OverriddenUsageInfo;
import com.intellij.refactoring.typeMigration.usageInfo.OverriderUsageInfo;
import com.intellij.refactoring.typeMigration.usageInfo.TypeMigrationUsageInfo;
import com.intellij.usageView.UsageInfo;
@@ -88,7 +88,7 @@ public class TypeMigrationLabeler {
private final Set<TypeMigrationUsageInfo> myProcessedRoots = new HashSet<>();
public TypeMigrationLabeler(final TypeMigrationRules rules, PsiType rootType) {
this(rules, Functions.<PsiElement, PsiType>constant(rootType));
this(rules, Functions.constant(rootType));
}
public TypeMigrationLabeler(final TypeMigrationRules rules, Function<PsiElement, PsiType> migrationRootTypeFunction) {
@@ -339,8 +339,8 @@ public class TypeMigrationLabeler {
}
else {
TypeMigrationReplacementUtil.migrateMemberOrVariableType(element, project, getTypeEvaluator().getType(usageInfo));
if (usageInfo instanceof OverridenUsageInfo) {
final String migrationName = ((OverridenUsageInfo)usageInfo).getMigrateMethodName();
if (usageInfo instanceof OverriddenUsageInfo) {
final String migrationName = ((OverriddenUsageInfo)usageInfo).getMigrateMethodName();
if (migrationName != null) {
ApplicationManager.getApplication().invokeLater(() -> new RenameProcessor(project, element, migrationName, false, false).run());
}
@@ -662,12 +662,12 @@ public class TypeMigrationLabeler {
for (int i = -1; i < methods.length; i++) {
final TypeMigrationUsageInfo m;
if (i < 0) {
final OverridenUsageInfo overridenUsageInfo = new OverridenUsageInfo(method);
m = overridenUsageInfo;
final OverriddenUsageInfo overriddenUsageInfo = new OverriddenUsageInfo(method);
m = overriddenUsageInfo;
final String newMethodName = isMethodNameCanBeChanged(method);
if (newMethodName != null) {
final MigrateGetterNameSetting migrateGetterNameSetting = myRules.getConversionSettings(MigrateGetterNameSetting.class);
migrateGetterNameSetting.askUserIfNeed(overridenUsageInfo, newMethodName, myTypeEvaluator.getType(myCurrentRoot));
migrateGetterNameSetting.askUserIfNeed(overriddenUsageInfo, newMethodName, myTypeEvaluator.getType(myCurrentRoot));
}
}
else {
@@ -687,13 +687,13 @@ public class TypeMigrationLabeler {
final PsiMethod[] methods = OverridingMethodsSearch.search(method).toArray(PsiMethod.EMPTY_ARRAY);
final OverriderUsageInfo[] overriders = new OverriderUsageInfo[methods.length];
final OverridenUsageInfo overridenUsageInfo = new OverridenUsageInfo(method.getParameterList().getParameters()[index]);
final OverriddenUsageInfo overriddenUsageInfo = new OverriddenUsageInfo(method.getParameterList().getParameters()[index]);
for (int i = -1; i < methods.length; i++) {
final PsiMethod m = i < 0 ? method : methods[i];
final PsiParameter p = m.getParameterList().getParameters()[index];
final TypeMigrationUsageInfo paramUsageInfo;
if (i < 0) {
paramUsageInfo = overridenUsageInfo;
paramUsageInfo = overriddenUsageInfo;
}
else {
overriders[i] = new OverriderUsageInfo(p, method);
@@ -924,7 +924,7 @@ public class TypeMigrationLabeler {
}
}
Collections.sort(validReferences, (o1, o2) -> o1.getElement().getTextOffset() - o2.getElement().getTextOffset());
Collections.sort(validReferences, Comparator.comparingInt(o -> o.getElement().getTextOffset()));
return validReferences.toArray(new PsiReference[validReferences.size()]);
}
@@ -1040,8 +1040,7 @@ public class TypeMigrationLabeler {
}
private void iterate() {
final LinkedList<Pair<TypeMigrationUsageInfo, PsiType>> roots =
(LinkedList<Pair<TypeMigrationUsageInfo, PsiType>>)myMigrationRoots.clone();
final List<Pair<TypeMigrationUsageInfo, PsiType>> roots = new ArrayList<>(myMigrationRoots);
myMigrationRoots = new LinkedList<>();
@@ -45,11 +45,10 @@ import java.util.*;
import static com.intellij.util.ObjectUtils.assertNotNull;
public class TypeMigrationProcessor extends BaseRefactoringProcessor {
private final static Logger LOG = Logger.getInstance(TypeMigrationProcessor.class);
private final static int MAX_ROOT_IN_PREVIEW_PRESENTATION = 3;
private PsiElement[] myRoot;
private Function<PsiElement, PsiType> myRootTypes;
private final Function<PsiElement, PsiType> myRootTypes;
private final TypeMigrationRules myRules;
private TypeMigrationLabeler myLabeler;
@@ -74,7 +73,7 @@ public class TypeMigrationProcessor extends BaseRefactoringProcessor {
final PsiElement root,
final PsiType migrationType,
final boolean optimizeImports) {
runHighlightingTypeMigration(project, editor, rules, new PsiElement[] {root}, Functions.<PsiElement, PsiType>constant(migrationType), optimizeImports);
runHighlightingTypeMigration(project, editor, rules, new PsiElement[] {root}, Functions.constant(migrationType), optimizeImports);
}
@@ -202,7 +202,7 @@ class TypeMigrationStatementProcessor extends JavaRecursiveElementVisitor {
final PsiType valueType = myTypeEvaluator.evaluateType(value);
if (returnType != null && valueType != null) {
if (!myLabeler.addMigrationRoot(method, valueType, myStatement, TypeConversionUtil.isAssignable(returnType, valueType) && !isGetter(value, method), true, true)
&& TypeMigrationLabeler.typeContainsTypeParameters(returnType, Collections.<PsiTypeParameter>emptySet())) {
&& TypeMigrationLabeler.typeContainsTypeParameters(returnType, Collections.emptySet())) {
value.accept(this);
}
}
@@ -638,7 +638,7 @@ class TypeMigrationStatementProcessor extends JavaRecursiveElementVisitor {
PsiType type = myTypeEvaluator.evaluateType(expr);
type = type instanceof PsiEllipsisType ? ((PsiEllipsisType)type).toArrayType() : type;
myType = GenericsUtil.getVariableTypeByExpressionType(type);
myChanged = (myOriginType == null || myType == null) ? false : !myType.equals(myOriginType);
myChanged = !(myOriginType == null || myType == null) && !myType.equals(myOriginType);
}
public TypeView(PsiVariable var, PsiSubstitutor varSubstitutor, PsiSubstitutor evalSubstitutor) {
@@ -649,7 +649,7 @@ class TypeMigrationStatementProcessor extends JavaRecursiveElementVisitor {
if (evalSubstitutor != null) realMap.putAll(evalSubstitutor.getSubstitutionMap());
myType = PsiSubstitutorImpl.createSubstitutor(realMap).substitute(myTypeEvaluator.getType(var));
myChanged = (myOriginType == null || myType == null) ? false : !myType.equals(myOriginType);
myChanged = !(myOriginType == null || myType == null) && !myType.equals(myOriginType);
}
public PsiType getType() {
@@ -34,12 +34,6 @@ public class ChangeTypeSignatureAction extends BaseRefactoringAction {
}
public boolean isEnabledOnElements(@NotNull PsiElement[] elements) {
Project currProject = CommonDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext());
if (currProject == null) {
return false;
}
if (elements.length > 1) return false;
for (PsiElement element : elements) {
@@ -65,7 +65,7 @@ public class RootTypeConversionRule extends TypeConversionRule {
if (Comparing.equal(functionalInterfaceType, to) && method.isEquivalentTo(LambdaUtil.getFunctionalInterfaceMethod(from))) {
return new TypeConversionDescriptorBase() {
@Override
public PsiExpression replace(PsiExpression expression, TypeEvaluator evaluator) throws IncorrectOperationException {
public PsiExpression replace(PsiExpression expression, @NotNull TypeEvaluator evaluator) throws IncorrectOperationException {
final PsiMethodReferenceExpression methodReferenceExpression = (PsiMethodReferenceExpression)expression;
final PsiExpression qualifierExpression = methodReferenceExpression.getQualifierExpression();
if (qualifierExpression != null) {
@@ -147,7 +147,7 @@ public class RootTypeConversionRule extends TypeConversionRule {
}
@Override
public PsiExpression replace(PsiExpression expression, TypeEvaluator evaluator) throws IncorrectOperationException {
public PsiExpression replace(PsiExpression expression, @NotNull TypeEvaluator evaluator) throws IncorrectOperationException {
final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)expression;
final PsiExpression qualifierExpression = methodCallExpression.getMethodExpression().getQualifierExpression();
final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(expression.getProject());
@@ -59,7 +59,7 @@ public class FailedConversionsDialog extends DialogWrapper {
panel.add(new JLabel(RefactoringBundle.message("the.following.problems.were.found")), BorderLayout.NORTH);
panel.add(scrollPane, BorderLayout.CENTER);
@NonNls StringBuffer buf = new StringBuffer();
@NonNls StringBuilder buf = new StringBuilder();
for (String description : myConflictDescriptions) {
buf.append(description);
buf.append("<br><br>");
@@ -121,8 +121,4 @@ public class MigrationNode extends AbstractTreeNode<TypeMigrationUsageInfo> impl
public MigrationNode getDuplicate() {
return myDuplicatedNode;
}
public boolean hasDuplicate() {
return myDuplicatedNode != null;
}
}
@@ -187,15 +187,14 @@ public class MigrationPanel extends JPanel implements Disposable {
if (userObject instanceof MigrationRootNode) {
ProgressManager.getInstance().runProcessWithProgressSynchronously(() -> {
final HashSet<VirtualFile> files = new HashSet<>();
final TypeMigrationUsageInfo[] usages = ApplicationManager.getApplication().runReadAction(new Computable<TypeMigrationUsageInfo[]>() {
@Override
public TypeMigrationUsageInfo[] compute() {
final TypeMigrationUsageInfo[] usages = ApplicationManager.getApplication().runReadAction(
(Computable<TypeMigrationUsageInfo[]>)() -> {
final Collection<? extends AbstractTreeNode> children = ((MigrationRootNode)userObject).getChildren();
for (AbstractTreeNode child : children) {
expandTree((MigrationNode)child);
}
final TypeMigrationUsageInfo[] usages = myLabeler.getMigratedUsages();
for (TypeMigrationUsageInfo usage : usages) {
final TypeMigrationUsageInfo[] usages1 = myLabeler.getMigratedUsages();
for (TypeMigrationUsageInfo usage : usages1) {
if (!usage.isExcluded()) {
final PsiElement element = usage.getElement();
if (element != null) {
@@ -203,9 +202,8 @@ public class MigrationPanel extends JPanel implements Disposable {
}
}
}
return usages;
}
});
return usages1;
});
ApplicationManager.getApplication().invokeLater(() -> {
@@ -306,7 +304,7 @@ public class MigrationPanel extends JPanel implements Disposable {
}
public Object getData(@NonNls final String dataId) {
if (DataConstants.PSI_ELEMENT.equals(dataId)) {
if (CommonDataKeys.PSI_ELEMENT.is(dataId)) {
final DefaultMutableTreeNode[] selectedNodes = getSelectedNodes(DefaultMutableTreeNode.class, null);
return selectedNodes.length == 1 && selectedNodes[0].getUserObject() instanceof MigrationNode
? ((MigrationNode)selectedNodes[0].getUserObject()).getInfo().getElement() : null;
@@ -37,7 +37,7 @@ import java.util.*;
public class MigrationRootNode extends AbstractTreeNode<TypeMigrationLabeler> implements DuplicateNodeRenderer.DuplicatableNode {
private final TypeMigrationLabeler myLabeler;
private List<MigrationNode> myCachedChildren;
private final PsiElement myRoots[];
private final PsiElement[] myRoots;
private final boolean myPreviewUsages;
protected MigrationRootNode(Project project,
@@ -22,10 +22,10 @@ import org.jetbrains.annotations.NotNull;
* @author anna
* Date: 27-Mar-2008
*/
public class OverridenUsageInfo extends TypeMigrationUsageInfo {
public class OverriddenUsageInfo extends TypeMigrationUsageInfo {
private volatile String myMigrateMethodName;
public OverridenUsageInfo(@NotNull PsiElement element) {
public OverriddenUsageInfo(@NotNull PsiElement element) {
super(element);
}