use of com.intellij.refactoring.typeMigration.TypeEvaluator in project intellij-community by JetBrains.
the class RootTypeConversionRule method findConversion.
public TypeConversionDescriptorBase findConversion(final PsiType from, final PsiType to, final PsiMember member, final PsiExpression context, final TypeMigrationLabeler labeler) {
if (member != null && to instanceof PsiClassType && from instanceof PsiClassType) {
final PsiClass targetClass = ((PsiClassType) to).resolve();
if (targetClass != null && member.isPhysical()) {
if (member instanceof PsiMethod) {
PsiMethod method = (PsiMethod) member;
PsiMethod replacer = targetClass.findMethodBySignature(method, true);
if (replacer == null) {
for (PsiMethod superMethod : method.findDeepestSuperMethods()) {
replacer = targetClass.findMethodBySignature(superMethod, true);
if (replacer != null) {
method = superMethod;
break;
}
}
}
if (replacer != null) {
final boolean isStaticMethodConversion = replacer.hasModifierProperty(PsiModifier.STATIC);
boolean isValid = isStaticMethodConversion ? TypeConversionUtil.areTypesConvertible(method.getReturnType(), from) && TypeConversionUtil.areTypesConvertible(replacer.getReturnType(), to) : TypeConversionUtil.areTypesConvertible(method.getReturnType(), replacer.getReturnType());
if (isValid) {
final PsiElement parent = context.getParent();
if (context instanceof PsiMethodReferenceExpression) {
final PsiType functionalInterfaceType = ((PsiMethodReferenceExpression) context).getFunctionalInterfaceType();
if (Comparing.equal(functionalInterfaceType, to) && method.isEquivalentTo(LambdaUtil.getFunctionalInterfaceMethod(from))) {
return new TypeConversionDescriptorBase() {
@Override
public PsiExpression replace(PsiExpression expression, @NotNull TypeEvaluator evaluator) throws IncorrectOperationException {
final PsiMethodReferenceExpression methodReferenceExpression = (PsiMethodReferenceExpression) expression;
final PsiExpression qualifierExpression = methodReferenceExpression.getQualifierExpression();
if (qualifierExpression != null) {
return (PsiExpression) expression.replace(qualifierExpression);
} else {
return expression;
}
}
};
}
}
if (context instanceof PsiReferenceExpression && parent instanceof PsiMethodCallExpression) {
final JavaResolveResult resolveResult = ((PsiReferenceExpression) context).advancedResolve(false);
final PsiSubstitutor aSubst;
final PsiReferenceExpression methodExpression = ((PsiMethodCallExpression) parent).getMethodExpression();
final PsiExpression qualifier = methodExpression.getQualifierExpression();
final PsiClass substitutionClass = method.getContainingClass();
if (qualifier != null) {
final PsiType evaluatedQualifierType = labeler.getTypeEvaluator().evaluateType(qualifier);
if (evaluatedQualifierType instanceof PsiClassType) {
aSubst = ((PsiClassType) evaluatedQualifierType).resolveGenerics().getSubstitutor();
} else {
aSubst = PsiSubstitutor.EMPTY;
}
} else {
aSubst = TypeConversionUtil.getClassSubstitutor(member.getContainingClass(), substitutionClass, PsiSubstitutor.EMPTY);
}
final PsiParameter[] originalParams = ((PsiMethod) member).getParameterList().getParameters();
final PsiParameter[] migrationParams = replacer.getParameterList().getParameters();
final PsiExpression[] actualParams = ((PsiMethodCallExpression) parent).getArgumentList().getExpressions();
assert originalParams.length == migrationParams.length;
final PsiSubstitutor methodTypeParamsSubstitutor = labeler.getTypeEvaluator().createMethodSubstitution(originalParams, actualParams, method, context, aSubst != null ? aSubst : PsiSubstitutor.EMPTY, true);
for (int i = 0; i < originalParams.length; i++) {
final PsiType originalType = resolveResult.getSubstitutor().substitute(originalParams[i].getType());
PsiType type = migrationParams[i].getType();
if (InheritanceUtil.isInheritorOrSelf(targetClass, substitutionClass, true)) {
final PsiSubstitutor superClassSubstitutor = TypeConversionUtil.getClassSubstitutor(substitutionClass, targetClass, PsiSubstitutor.EMPTY);
assert (superClassSubstitutor != null);
type = superClassSubstitutor.substitute(type);
}
final PsiType migrationType = methodTypeParamsSubstitutor.substitute(type);
if (!originalType.equals(migrationType) && !areParametersAssignable(migrationType, i, actualParams)) {
if (migrationType instanceof PsiEllipsisType && actualParams.length != migrationParams.length) {
return null;
}
labeler.migrateExpressionType(actualParams[i], migrationType, context, false, true);
}
}
}
return isStaticMethodConversion ? new MyStaticMethodConversionDescriptor(targetClass) : new TypeConversionDescriptorBase();
}
}
} else if (member instanceof PsiField) {
final PsiClass fieldContainingClass = member.getContainingClass();
if (InheritanceUtil.isInheritorOrSelf(targetClass, fieldContainingClass, true)) {
return new TypeConversionDescriptorBase();
}
}
}
}
return null;
}
use of com.intellij.refactoring.typeMigration.TypeEvaluator in project intellij-community by JetBrains.
the class AtomicConversionRule method findDirectConversion.
@Nullable
public static TypeConversionDescriptor findDirectConversion(PsiElement context, PsiType to, PsiType from) {
final PsiClass toTypeClass = PsiUtil.resolveClassInType(to);
LOG.assertTrue(toTypeClass != null);
final String qualifiedName = toTypeClass.getQualifiedName();
if (qualifiedName != null) {
if (qualifiedName.equals(AtomicInteger.class.getName()) || qualifiedName.equals(AtomicLong.class.getName())) {
if (context instanceof PsiPostfixExpression) {
final IElementType operationSign = ((PsiPostfixExpression) context).getOperationTokenType();
if (operationSign == JavaTokenType.MINUSMINUS) {
return new TypeConversionDescriptor("$qualifier$--", "$qualifier$.getAndDecrement()");
}
if (operationSign == JavaTokenType.PLUSPLUS) {
return new TypeConversionDescriptor("$qualifier$++", "$qualifier$.getAndIncrement()");
}
} else if (context instanceof PsiPrefixExpression) {
final IElementType operationSign = ((PsiPrefixExpression) context).getOperationTokenType();
if (operationSign == JavaTokenType.MINUSMINUS) {
return new TypeConversionDescriptor("--$qualifier$", "$qualifier$.decrementAndGet()");
}
if (operationSign == JavaTokenType.PLUSPLUS) {
return new TypeConversionDescriptor("++$qualifier$", "$qualifier$.incrementAndGet()");
}
} else if (context instanceof PsiAssignmentExpression) {
final PsiJavaToken signToken = ((PsiAssignmentExpression) context).getOperationSign();
final IElementType operationSign = signToken.getTokenType();
final String sign = signToken.getText();
if (operationSign == JavaTokenType.PLUSEQ || operationSign == JavaTokenType.MINUSEQ) {
return new TypeConversionDescriptor("$qualifier$ " + sign + " $val$", "$qualifier$.addAndGet(" + (operationSign == JavaTokenType.MINUSEQ ? "-($val$))" : "$val$)")) {
@Override
public PsiExpression replace(PsiExpression expression, @NotNull TypeEvaluator evaluator) {
final PsiMethodCallExpression result = (PsiMethodCallExpression) super.replace(expression, evaluator);
final PsiExpression argument = result.getArgumentList().getExpressions()[0];
if (argument instanceof PsiPrefixExpression) {
final PsiExpression operand = ((PsiPrefixExpression) argument).getOperand();
final PsiExpression striped = ParenthesesUtils.stripParentheses(operand);
if (striped != null && operand != striped) {
operand.replace(striped);
}
}
return result;
}
};
}
} else if (context instanceof PsiLiteralExpression && !(context.getParent() instanceof PsiAssignmentExpression)) {
return wrapWithNewExpression(to, from, (PsiExpression) context, context);
}
} else if (qualifiedName.equals(AtomicIntegerArray.class.getName()) || qualifiedName.equals(AtomicLongArray.class.getName())) {
PsiElement parentExpression = context.getParent();
if (parentExpression instanceof PsiPostfixExpression) {
final IElementType operationSign = ((PsiPostfixExpression) parentExpression).getOperationTokenType();
if (operationSign == JavaTokenType.MINUSMINUS) {
return new TypeConversionDescriptor("$qualifier$[$idx$]--", "$qualifier$.getAndDecrement($idx$)", (PsiExpression) parentExpression);
}
if (operationSign == JavaTokenType.PLUSPLUS) {
return new TypeConversionDescriptor("$qualifier$[$idx$]++", "$qualifier$.getAndIncrement($idx$)", (PsiExpression) parentExpression);
}
} else if (parentExpression instanceof PsiPrefixExpression) {
final IElementType operationSign = ((PsiPrefixExpression) parentExpression).getOperationTokenType();
if (operationSign == JavaTokenType.MINUSMINUS) {
return new TypeConversionDescriptor("--$qualifier$[$idx$]", "$qualifier$.decrementAndGet($idx$)", (PsiExpression) parentExpression);
}
if (operationSign == JavaTokenType.PLUSPLUS) {
return new TypeConversionDescriptor("++$qualifier$[$idx$]", "$qualifier$.incrementAndGet($idx$)", (PsiExpression) parentExpression);
}
} else if (parentExpression instanceof PsiAssignmentExpression) {
final PsiJavaToken signToken = ((PsiAssignmentExpression) parentExpression).getOperationSign();
final IElementType operationSign = signToken.getTokenType();
final String sign = signToken.getText();
if (operationSign == JavaTokenType.PLUSEQ || operationSign == JavaTokenType.MINUSEQ) {
return new TypeConversionDescriptor("$qualifier$[$idx$] " + sign + " $val$", "$qualifier$.getAndAdd($idx$, " + (operationSign == JavaTokenType.MINUSEQ ? "-" : "") + "($val$))", (PsiExpression) parentExpression);
}
}
}
}
return from instanceof PsiArrayType ? findDirectConversionForAtomicReferenceArray(context, to, from) : findDirectConversionForAtomicReference(context, to, from);
}
use of com.intellij.refactoring.typeMigration.TypeEvaluator in project intellij-community by JetBrains.
the class VoidConversionRule method findConversion.
@Nullable
@Override
public TypeConversionDescriptorBase findConversion(PsiType from, PsiType to, PsiMember member, PsiExpression context, TypeMigrationLabeler labeler) {
if (PsiType.VOID.equals(to) && context.getParent() instanceof PsiReturnStatement && !SideEffectChecker.mayHaveSideEffects(context)) {
return new TypeConversionDescriptorBase() {
@Override
public PsiExpression replace(PsiExpression expression, @NotNull TypeEvaluator evaluator) throws IncorrectOperationException {
final PsiElement parent = expression.getParent();
final Project project = expression.getProject();
if (parent instanceof PsiReturnStatement) {
final PsiReturnStatement replaced = (PsiReturnStatement) parent.replace(JavaPsiFacade.getElementFactory(project).createStatementFromText("return;", null));
if (UnnecessaryReturnInspection.isReturnRedundant(replaced, false, null)) {
DeleteUnnecessaryStatementFix.deleteUnnecessaryStatement(replaced);
}
}
return null;
}
};
}
return null;
}
use of com.intellij.refactoring.typeMigration.TypeEvaluator in project intellij-community by JetBrains.
the class ConvertFieldToAtomicIntention method invoke.
@Override
public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException {
final PsiVariable psiVariable = getVariable(element);
LOG.assertTrue(psiVariable != null);
final Query<PsiReference> refs = ReferencesSearch.search(psiVariable);
final Set<PsiElement> elements = new HashSet<>();
elements.add(element);
for (PsiReference reference : refs) {
elements.add(reference.getElement());
}
if (!FileModificationService.getInstance().preparePsiElementsForWrite(elements))
return;
psiVariable.normalizeDeclaration();
final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project);
final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
final PsiType fromType = psiVariable.getType();
PsiClassType toType;
final String atomicQualifiedName = myFromToMap.get(fromType);
if (atomicQualifiedName != null) {
final PsiClass atomicClass = psiFacade.findClass(atomicQualifiedName, GlobalSearchScope.allScope(project));
if (atomicClass == null) {
//show warning
return;
}
toType = factory.createType(atomicClass);
} else if (fromType instanceof PsiArrayType) {
final PsiClass atomicReferenceArrayClass = psiFacade.findClass(AtomicReferenceArray.class.getName(), GlobalSearchScope.allScope(project));
if (atomicReferenceArrayClass == null) {
//show warning
return;
}
final Map<PsiTypeParameter, PsiType> substitutor = ContainerUtil.newHashMap();
final PsiTypeParameter[] typeParameters = atomicReferenceArrayClass.getTypeParameters();
if (typeParameters.length == 1) {
PsiType componentType = ((PsiArrayType) fromType).getComponentType();
if (componentType instanceof PsiPrimitiveType)
componentType = ((PsiPrimitiveType) componentType).getBoxedType(element);
substitutor.put(typeParameters[0], componentType);
}
toType = factory.createType(atomicReferenceArrayClass, factory.createSubstitutor(substitutor));
} else {
final PsiClass atomicReferenceClass = psiFacade.findClass(AtomicReference.class.getName(), GlobalSearchScope.allScope(project));
if (atomicReferenceClass == null) {
//show warning
return;
}
final Map<PsiTypeParameter, PsiType> substitutor = ContainerUtil.newHashMap();
final PsiTypeParameter[] typeParameters = atomicReferenceClass.getTypeParameters();
if (typeParameters.length == 1) {
PsiType type = fromType;
if (type instanceof PsiPrimitiveType)
type = ((PsiPrimitiveType) fromType).getBoxedType(element);
substitutor.put(typeParameters[0], type);
}
toType = factory.createType(atomicReferenceClass, factory.createSubstitutor(substitutor));
}
try {
for (PsiReference reference : refs) {
PsiElement refElement = reference.getElement();
PsiElement psiElement = refElement;
if (psiElement instanceof PsiExpression) {
final PsiElement parent = psiElement.getParent();
if (parent instanceof PsiExpression && !(parent instanceof PsiReferenceExpression || parent instanceof PsiPolyadicExpression)) {
psiElement = parent;
}
if (psiElement instanceof PsiBinaryExpression) {
PsiBinaryExpression binary = (PsiBinaryExpression) psiElement;
if (isBinaryOpApplicable(binary.getOperationTokenType(), binary.getLOperand(), binary.getROperand(), refElement, toType)) {
continue;
}
} else if (psiElement instanceof PsiAssignmentExpression) {
final PsiAssignmentExpression assignment = (PsiAssignmentExpression) psiElement;
final IElementType opSign = TypeConversionUtil.convertEQtoOperation(assignment.getOperationTokenType());
if (isBinaryOpApplicable(opSign, assignment.getLExpression(), assignment.getRExpression(), refElement, toType)) {
continue;
}
}
final TypeConversionDescriptor directConversion = AtomicConversionRule.findDirectConversion(psiElement, toType, fromType);
if (directConversion != null) {
TypeMigrationReplacementUtil.replaceExpression((PsiExpression) psiElement, project, directConversion, new TypeEvaluator(null, null));
}
}
}
PsiExpression initializer = psiVariable.getInitializer();
if (initializer != null) {
if (initializer instanceof PsiArrayInitializerExpression) {
PsiExpression normalizedExpr = RefactoringUtil.createNewExpressionFromArrayInitializer((PsiArrayInitializerExpression) initializer, psiVariable.getType());
initializer = (PsiExpression) initializer.replace(normalizedExpr);
}
final TypeConversionDescriptor directConversion = AtomicConversionRule.wrapWithNewExpression(toType, fromType, initializer, element);
if (directConversion != null) {
TypeMigrationReplacementUtil.replaceExpression(initializer, project, directConversion, new TypeEvaluator(null, null));
}
} else if (!assertNotNull(psiVariable.getModifierList()).hasModifierProperty(PsiModifier.FINAL)) {
final PsiExpression newInitializer = factory.createExpressionFromText("new " + toType.getCanonicalText() + "()", psiVariable);
if (psiVariable instanceof PsiLocalVariable) {
((PsiLocalVariable) psiVariable).setInitializer(newInitializer);
} else if (psiVariable instanceof PsiField) {
((PsiField) psiVariable).setInitializer(newInitializer);
}
JavaCodeStyleManager.getInstance(project).shortenClassReferences(psiVariable.getInitializer());
}
PsiElement replaced = assertNotNull(psiVariable.getTypeElement()).replace(factory.createTypeElement(toType));
JavaCodeStyleManager.getInstance(project).shortenClassReferences(replaced);
if (psiVariable instanceof PsiField || CodeStyleSettingsManager.getSettings(project).GENERATE_FINAL_LOCALS) {
final PsiModifierList modifierList = assertNotNull(psiVariable.getModifierList());
modifierList.setModifierProperty(PsiModifier.FINAL, true);
modifierList.setModifierProperty(PsiModifier.VOLATILE, false);
}
} catch (IncorrectOperationException e) {
LOG.error(e);
}
}
use of com.intellij.refactoring.typeMigration.TypeEvaluator in project intellij-community by JetBrains.
the class GuavaFluentIterableConversionRule method getOneMethodDescriptor.
@Nullable
private static TypeConversionDescriptorBase getOneMethodDescriptor(@NotNull String methodName, @NotNull PsiMethod method, @NotNull PsiType from, @Nullable PsiType to, @Nullable PsiExpression context) {
TypeConversionDescriptor descriptorBase = null;
PsiType conversionType = null;
boolean needSpecifyType = true;
if (methodName.equals("of")) {
descriptorBase = new TypeConversionDescriptor("'FluentIterable*.of($arr$)", "java.util.Arrays.stream($arr$)");
} else if (methodName.equals("from")) {
descriptorBase = new TypeConversionDescriptor("'FluentIterable*.from($it$)", null) {
@Override
public PsiExpression replace(PsiExpression expression, @NotNull TypeEvaluator evaluator) {
final PsiMethodCallExpression methodCall = (PsiMethodCallExpression) expression;
PsiExpression argument = PseudoLambdaReplaceTemplate.replaceTypeParameters(methodCall.getArgumentList().getExpressions()[0]);
if (argument == null) {
return expression;
}
boolean isCollection = InheritanceUtil.isInheritor(PsiTypesUtil.getPsiClass(argument.getType()), CommonClassNames.JAVA_UTIL_COLLECTION);
setReplaceByString(isCollection ? "($it$).stream()" : "java.util.stream.StreamSupport.stream(($it$).spliterator(), false)");
final PsiExpression replaced = super.replace(expression, evaluator);
ParenthesesUtils.removeParentheses(replaced, false);
return replaced;
}
};
} else if (methodName.equals("filter")) {
descriptorBase = FluentIterableConversionUtil.getFilterDescriptor(method, context);
} else if (methodName.equals("isEmpty")) {
descriptorBase = new TypeConversionDescriptor("$q$.isEmpty()", null) {
@Override
public PsiExpression replace(PsiExpression expression, @NotNull TypeEvaluator evaluator) {
final PsiElement parent = expression.getParent();
boolean isDoubleNegation = false;
if (parent instanceof PsiExpression && DoubleNegationInspection.isNegation((PsiExpression) parent)) {
isDoubleNegation = true;
expression = (PsiExpression) parent.replace(expression);
}
setReplaceByString((isDoubleNegation ? "" : "!") + "$q$.findAny().isPresent()");
return super.replace(expression, evaluator);
}
};
needSpecifyType = false;
} else if (methodName.equals("transformAndConcat")) {
descriptorBase = new FluentIterableConversionUtil.TransformAndConcatConversionRule();
} else if (methodName.equals("toArray")) {
descriptorBase = FluentIterableConversionUtil.getToArrayDescriptor(from, context);
needSpecifyType = false;
} else if (methodName.equals("copyInto")) {
descriptorBase = new FluentIterableConversionUtil.CopyIntoConversionDescriptor();
needSpecifyType = false;
} else if (methodName.equals("append")) {
descriptorBase = createDescriptorForAppend(method, context);
} else if (methodName.equals("get")) {
descriptorBase = new TypeConversionDescriptor("$it$.get($p$)", null) {
@Override
public PsiExpression replace(PsiExpression expression, @NotNull TypeEvaluator evaluator) {
PsiMethodCallExpression methodCall = (PsiMethodCallExpression) expression;
final PsiExpression[] arguments = methodCall.getArgumentList().getExpressions();
setReplaceByString("$it$.skip($p$).findFirst().get()");
if (arguments.length == 1 && arguments[0] instanceof PsiLiteralExpression) {
final Object value = ((PsiLiteralExpression) arguments[0]).getValue();
if (value != null && value.equals(0)) {
setReplaceByString("$it$.findFirst().get()");
}
}
return super.replace(expression, evaluator);
}
};
needSpecifyType = false;
} else if (methodName.equals("contains")) {
descriptorBase = new TypeConversionDescriptor("$it$.contains($o$)", null) {
@Override
public PsiExpression replace(PsiExpression expression, @NotNull TypeEvaluator evaluator) {
final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression) expression;
final PsiExpression qualifier = methodCallExpression.getMethodExpression().getQualifierExpression();
LOG.assertTrue(qualifier != null);
final PsiClassType qualifierType = (PsiClassType) qualifier.getType();
LOG.assertTrue(qualifierType != null);
final PsiType[] parameters = qualifierType.getParameters();
final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(expression.getProject());
final SuggestedNameInfo suggestedNameInfo = codeStyleManager.suggestVariableName(VariableKind.LOCAL_VARIABLE, null, null, parameters.length == 1 ? parameters[0] : null, false);
final String suggestedName = codeStyleManager.suggestUniqueVariableName(suggestedNameInfo, expression, false).names[0];
setReplaceByString("$it$.anyMatch(" + suggestedName + " -> java.util.Objects.equals(" + suggestedName + ", $o$))");
return super.replace(expression, evaluator);
}
};
needSpecifyType = false;
} else if (methodName.equals("last")) {
descriptorBase = new TypeConversionDescriptor("$it$.last()", null) {
@Override
public PsiExpression replace(PsiExpression expression, @NotNull TypeEvaluator evaluator) {
final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(expression.getProject());
String varA = suggestName("a", codeStyleManager, expression);
String varB = suggestName("b", codeStyleManager, expression);
setReplaceByString("$it$.reduce((" + varA + ", " + varB + ") -> " + varB + ")");
return super.replace(expression, evaluator);
}
private String suggestName(String baseName, JavaCodeStyleManager codeStyleManager, PsiElement place) {
final SuggestedNameInfo suggestedNameInfo = codeStyleManager.suggestVariableName(VariableKind.LOCAL_VARIABLE, baseName, null, null, false);
return codeStyleManager.suggestUniqueVariableName(suggestedNameInfo, place, false).names[0];
}
};
} else {
final TypeConversionDescriptorFactory base = DESCRIPTORS_MAP.get(methodName);
if (base != null) {
final TypeConversionDescriptor descriptor = base.create();
needSpecifyType = base.isChainedMethod();
if (needSpecifyType && !base.isFluentIterableReturnType()) {
conversionType = GuavaConversionUtil.addTypeParameters(GuavaOptionalConversionRule.JAVA_OPTIONAL, context.getType(), context);
}
descriptorBase = descriptor;
}
}
if (descriptorBase == null) {
return FluentIterableConversionUtil.createToCollectionDescriptor(methodName, context);
}
if (needSpecifyType) {
if (conversionType == null) {
PsiMethodCallExpression methodCall = (PsiMethodCallExpression) (context instanceof PsiMethodCallExpression ? context : context.getParent());
conversionType = GuavaConversionUtil.addTypeParameters(GuavaTypeConversionDescriptor.isIterable(methodCall) ? CommonClassNames.JAVA_LANG_ITERABLE : StreamApiConstants.JAVA_UTIL_STREAM_STREAM, context.getType(), context);
}
descriptorBase.withConversionType(conversionType);
}
return descriptorBase;
}
Aggregations