diff --git a/java/java-impl/src/com/intellij/codeInspection/miscGenerics/RawTypeCanBeGenericInspection.java b/java/java-impl/src/com/intellij/codeInspection/miscGenerics/RawTypeCanBeGenericInspection.java index cefbd93158c4..b0c7a79c9f6b 100644 --- a/java/java-impl/src/com/intellij/codeInspection/miscGenerics/RawTypeCanBeGenericInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/miscGenerics/RawTypeCanBeGenericInspection.java @@ -120,7 +120,7 @@ public class RawTypeCanBeGenericInspection extends BaseJavaBatchLocalInspectionT if (type != null) { final TypeMigrationRules rules = new TypeMigrationRules(); rules.setBoundScope(PsiSearchHelper.SERVICE.getInstance(project).getUseScope(variable)); - TypeMigrationProcessor.runHighlightingTypeMigration(project, null, rules, variable, type, false); + TypeMigrationProcessor.runHighlightingTypeMigration(project, null, rules, variable, type, false, true); } } } diff --git a/java/java-impl/src/com/intellij/refactoring/extractclass/ExtractEnumProcessor.java b/java/java-impl/src/com/intellij/refactoring/extractclass/ExtractEnumProcessor.java index a31e18af64fd..8d1b79fb4555 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractclass/ExtractEnumProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/extractclass/ExtractEnumProcessor.java @@ -147,7 +147,8 @@ public class ExtractEnumProcessor { myTypeMigrationProcessor = new TypeMigrationProcessor(myProject, PsiUtilCore.toPsiElementArray(myEnumConstants), Functions.constant(JavaPsiFacade.getElementFactory(myProject).createType(myClass)), - rules); + rules, + true); for (UsageInfo usageInfo : myTypeMigrationProcessor.findUsages()) { final PsiElement migrateElement = usageInfo.getElement(); if (migrateElement instanceof PsiField) { diff --git a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationLabeler.java b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationLabeler.java index 99f08d727966..cf02b871b77e 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationLabeler.java +++ b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationLabeler.java @@ -74,6 +74,7 @@ public class TypeMigrationLabeler { private final TypeMigrationRules myRules; private final Function myMigrationRootTypeFunction; + @Nullable private final Set myAllowedRoots; private TypeEvaluator myTypeEvaluator; private final LinkedHashMap myConversions; private final Map, PsiType>, TypeMigrationUsageInfo> myFailedConversions; @@ -89,13 +90,16 @@ public class TypeMigrationLabeler { private final Map, Set> myRootUsagesTree = new HashMap<>(); private final Set myProcessedRoots = new HashSet<>(); - public TypeMigrationLabeler(final TypeMigrationRules rules, PsiType rootType) { - this(rules, Functions.constant(rootType)); + public TypeMigrationLabeler(TypeMigrationRules rules, PsiType rootType) { + this(rules, Functions.constant(rootType), null); } - public TypeMigrationLabeler(final TypeMigrationRules rules, Function migrationRootTypeFunction) { + public TypeMigrationLabeler(TypeMigrationRules rules, + Function migrationRootTypeFunction, + @Nullable("any root accepted if null") PsiElement[] allowedRoots) { myRules = rules; myMigrationRootTypeFunction = migrationRootTypeFunction; + myAllowedRoots = allowedRoots == null ? null : ContainerUtil.set(allowedRoots); myConversions = new LinkedHashMap<>(); myFailedConversions = new LinkedHashMap<>(); @@ -574,6 +578,9 @@ public class TypeMigrationLabeler { boolean alreadyProcessed, final boolean isContraVariantPosition, final boolean userDefinedType) { + if (myAllowedRoots != null && !myAllowedRoots.contains(element)) { + return false; + } if (type.equals(PsiType.NULL)) { return false; } diff --git a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationProcessor.java b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationProcessor.java index 9f28389e9768..80a20cf336de 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationProcessor.java @@ -50,18 +50,25 @@ import java.util.Set; import static com.intellij.util.ObjectUtils.assertNotNull; public class TypeMigrationProcessor extends BaseRefactoringProcessor { + public volatile static boolean ourSkipFailedConversionInTestMode; private final static int MAX_ROOT_IN_PREVIEW_PRESENTATION = 3; private PsiElement[] myRoots; private final Function myRootTypes; + private final boolean myAllowDependentRoots; private final TypeMigrationRules myRules; private TypeMigrationLabeler myLabeler; - public TypeMigrationProcessor(final Project project, final PsiElement[] roots, final Function rootTypes, final TypeMigrationRules rules) { + public TypeMigrationProcessor(final Project project, + final PsiElement[] roots, + final Function rootTypes, + final TypeMigrationRules rules, + final boolean allowDependentRoots) { super(project); myRoots = roots; myRules = rules; myRootTypes = rootTypes; + myAllowDependentRoots = allowDependentRoots; } public static void runHighlightingTypeMigration(final Project project, @@ -69,7 +76,7 @@ public class TypeMigrationProcessor extends BaseRefactoringProcessor { final TypeMigrationRules rules, final PsiElement root, final PsiType migrationType) { - runHighlightingTypeMigration(project, editor, rules, root, migrationType, false); + runHighlightingTypeMigration(project, editor, rules, root, migrationType, false, true); } public static void runHighlightingTypeMigration(final Project project, @@ -77,8 +84,9 @@ public class TypeMigrationProcessor extends BaseRefactoringProcessor { final TypeMigrationRules rules, final PsiElement root, final PsiType migrationType, - final boolean optimizeImports) { - runHighlightingTypeMigration(project, editor, rules, new PsiElement[] {root}, Functions.constant(migrationType), optimizeImports); + final boolean optimizeImports, + boolean allowDependentRoots) { + runHighlightingTypeMigration(project, editor, rules, new PsiElement[] {root}, Functions.constant(migrationType), optimizeImports, allowDependentRoots); } @@ -87,9 +95,10 @@ public class TypeMigrationProcessor extends BaseRefactoringProcessor { final TypeMigrationRules rules, final PsiElement[] roots, final Function migrationTypeFunction, - final boolean optimizeImports) { - final Set containingFiles = ContainerUtil.map2Set(roots, element -> element.getContainingFile()); - final TypeMigrationProcessor processor = new TypeMigrationProcessor(project, roots, migrationTypeFunction, rules) { + final boolean optimizeImports, + boolean allowDependentRoots) { + final Set containingFiles = ContainerUtil.map2Set(roots, PsiElement::getContainingFile); + final TypeMigrationProcessor processor = new TypeMigrationProcessor(project, roots, migrationTypeFunction, rules, allowDependentRoots) { @Override public void performRefactoring(@NotNull final UsageInfo[] usages) { super.performRefactoring(usages); @@ -142,6 +151,10 @@ public class TypeMigrationProcessor extends BaseRefactoringProcessor { protected boolean preprocessUsages(@NotNull Ref refUsages) { if (hasFailedConversions()) { if (ApplicationManager.getApplication().isUnitTestMode()) { + if (ourSkipFailedConversionInTestMode) { + prepareSuccessful(); + return true; + } throw new BaseRefactoringProcessor.ConflictsInTestsException(Arrays.asList(myLabeler.getFailedConversionsReport())); } FailedConversionsDialog dialog = new FailedConversionsDialog(myLabeler.getFailedConversionsReport(), myProject); @@ -213,7 +226,7 @@ public class TypeMigrationProcessor extends BaseRefactoringProcessor { @NotNull @Override public UsageInfo[] findUsages() { - myLabeler = new TypeMigrationLabeler(myRules, myRootTypes); + myLabeler = new TypeMigrationLabeler(myRules, myRootTypes, myAllowDependentRoots ? null : myRoots); try { return myLabeler.getMigratedUsages(!isPreviewUsages(), myRoots); @@ -287,6 +300,7 @@ public class TypeMigrationProcessor extends BaseRefactoringProcessor { return myLabeler; } + @NotNull @Override protected String getCommandName() { return "TypeMigration"; diff --git a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationStatementProcessor.java b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationStatementProcessor.java index 51ad967a91da..7a23e5cb45a2 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationStatementProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationStatementProcessor.java @@ -386,6 +386,8 @@ class TypeMigrationStatementProcessor extends JavaRecursiveElementVisitor { final PsiExpression rOperand = operands[i]; if (rOperand == null) return; final TypeView right = new TypeView(rOperand); + if (tryFindConversionIfOperandIsNull(left, right, rOperand)) continue; + if (tryFindConversionIfOperandIsNull(right, left, lOperand)) continue; if (!TypeConversionUtil.isBinaryOperatorApplicable(operationTokenType, left.getType(), right.getType(), false)) { if (left.isChanged()) { findConversionOrFail(lOperand, lOperand, left.getTypePair()); @@ -399,6 +401,19 @@ class TypeMigrationStatementProcessor extends JavaRecursiveElementVisitor { } } + protected boolean tryFindConversionIfOperandIsNull(TypeView nullCandidate, TypeView comparingType, PsiExpression comparingExpr) { + if (nullCandidate.getType() == PsiType.NULL && comparingType.isChanged()) { + Pair typePair = comparingType.getTypePair(); + final TypeConversionDescriptorBase + conversion = myLabeler.getRules().findConversion(typePair.getFirst(), typePair.getSecond(), null, comparingExpr, false, myLabeler); + if (conversion != null) { + myLabeler.setConversionMapping(comparingExpr, conversion); + } + return true; + } + return false; + } + private void processArrayInitializer(final PsiArrayInitializerExpression expression, final PsiExpression parentExpression) { final PsiExpression[] initializers = expression.getInitializers(); PsiType migrationType = null; @@ -593,6 +608,7 @@ class TypeMigrationStatementProcessor extends JavaRecursiveElementVisitor { } } + private static boolean canBeVariableType(@NotNull PsiType type) { return !type.getDeepComponentType().equals(PsiType.VOID); } diff --git a/java/java-impl/src/com/intellij/refactoring/typeMigration/ui/TypeMigrationDialog.java b/java/java-impl/src/com/intellij/refactoring/typeMigration/ui/TypeMigrationDialog.java index 7451fd065d6f..bea30d1fabbd 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeMigration/ui/TypeMigrationDialog.java +++ b/java/java-impl/src/com/intellij/refactoring/typeMigration/ui/TypeMigrationDialog.java @@ -98,7 +98,7 @@ public abstract class TypeMigrationDialog extends RefactoringDialog { myRules = new TypeMigrationRules(); myRules.setBoundScope(myScopeChooserCombo.getSelectedScope()); } - invokeRefactoring(new TypeMigrationProcessor(myProject, myRoots, getMigrationTypeFunction(), myRules)); + invokeRefactoring(new TypeMigrationProcessor(myProject, myRoots, getMigrationTypeFunction(), myRules, true)); } @NotNull diff --git a/java/typeMigration/src/com/intellij/refactoring/typeMigration/TypeConversionDescriptor.java b/java/typeMigration/src/com/intellij/refactoring/typeMigration/TypeConversionDescriptor.java index d25cc9543633..529b52be6a25 100644 --- a/java/typeMigration/src/com/intellij/refactoring/typeMigration/TypeConversionDescriptor.java +++ b/java/typeMigration/src/com/intellij/refactoring/typeMigration/TypeConversionDescriptor.java @@ -1,6 +1,5 @@ package com.intellij.refactoring.typeMigration; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.project.Project; import com.intellij.psi.JavaPsiFacade; @@ -15,8 +14,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public class TypeConversionDescriptor extends TypeConversionDescriptorBase { - private static final Logger LOG = Logger.getInstance(TypeConversionDescriptor.class); - private String myStringToReplace = null; private String myReplaceByString = "$"; private PsiExpression myExpression; @@ -75,9 +72,15 @@ public class TypeConversionDescriptor extends TypeConversionDescriptorBase { @Override public PsiExpression replace(PsiExpression expression, @NotNull TypeEvaluator evaluator) { if (getExpression() != null) expression = getExpression(); + expression = adjustExpressionBeforeReplacement(expression); return replaceExpression(expression, getStringToReplace(), getReplaceByString()); } + @NotNull + protected PsiExpression adjustExpressionBeforeReplacement(@NotNull PsiExpression expression) { + return expression; + } + @NotNull public static PsiExpression replaceExpression(@NotNull PsiExpression expression, String stringToReplace, diff --git a/java/typeMigration/src/com/intellij/refactoring/typeMigration/TypeMigrationVariableTypeFixProvider.java b/java/typeMigration/src/com/intellij/refactoring/typeMigration/TypeMigrationVariableTypeFixProvider.java index 673d0c501d8e..7089f63bc112 100644 --- a/java/typeMigration/src/com/intellij/refactoring/typeMigration/TypeMigrationVariableTypeFixProvider.java +++ b/java/typeMigration/src/com/intellij/refactoring/typeMigration/TypeMigrationVariableTypeFixProvider.java @@ -50,7 +50,7 @@ public class TypeMigrationVariableTypeFixProvider implements ChangeVariableTypeQ @Nullable("is null when called from inspection") Editor editor, @NotNull PsiElement startElement, @NotNull PsiElement endElement) { - runTypeMigrationOnVariable((PsiVariable)startElement, getReturnType(), editor, optimizeImports); + runTypeMigrationOnVariable((PsiVariable)startElement, getReturnType(), editor, optimizeImports, true); } @Override @@ -63,14 +63,15 @@ public class TypeMigrationVariableTypeFixProvider implements ChangeVariableTypeQ public static void runTypeMigrationOnVariable(@NotNull PsiVariable variable, @NotNull PsiType targetType, @Nullable("is null when called from inspection") Editor editor, - boolean optimizeImports) { + boolean optimizeImports, + boolean allowDependentRoots) { Project project = variable.getProject(); if (!FileModificationService.getInstance().prepareFileForWrite(variable.getContainingFile())) return; try { WriteAction.run(() -> variable.normalizeDeclaration()); final TypeMigrationRules rules = new TypeMigrationRules(); rules.setBoundScope(GlobalSearchScope.projectScope(project)); - TypeMigrationProcessor.runHighlightingTypeMigration(project, editor, rules, variable, targetType, optimizeImports); + TypeMigrationProcessor.runHighlightingTypeMigration(project, editor, rules, variable, targetType, optimizeImports, allowDependentRoots); WriteAction.run(() -> JavaCodeStyleManager.getInstance(project).shortenClassReferences(variable)); UndoUtil.markPsiFileForUndo(variable.getContainingFile()); } diff --git a/java/typeMigration/src/com/intellij/refactoring/typeMigration/inspections/GuavaInspection.java b/java/typeMigration/src/com/intellij/refactoring/typeMigration/inspections/GuavaInspection.java index 23de3c3fb7a7..f44dd37496b2 100644 --- a/java/typeMigration/src/com/intellij/refactoring/typeMigration/inspections/GuavaInspection.java +++ b/java/typeMigration/src/com/intellij/refactoring/typeMigration/inspections/GuavaInspection.java @@ -359,6 +359,7 @@ public class GuavaInspection extends BaseJavaLocalInspectionTool { rules, elements.toArray(new PsiElement[elements.size()]), createMigrationTypeFunction(elements, types), + true, true); } diff --git a/java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ConvertAtomicToLongAdderIntention.java b/java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ConvertAtomicToLongAdderIntention.java index 609b63b4c8de..15e397c09558 100644 --- a/java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ConvertAtomicToLongAdderIntention.java +++ b/java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ConvertAtomicToLongAdderIntention.java @@ -41,7 +41,7 @@ public class ConvertAtomicToLongAdderIntention extends PsiElementBaseIntentionAc if (variable != null) { final PsiType longAdder = JavaPsiFacade.getElementFactory(project).createTypeFromText(LongAdderConversionRule.JAVA_UTIL_CONCURRENT_ATOMIC_LONG_ADDER, element); - TypeMigrationVariableTypeFixProvider.runTypeMigrationOnVariable(variable, longAdder, null, false); + TypeMigrationVariableTypeFixProvider.runTypeMigrationOnVariable(variable, longAdder, null, false, false); } } diff --git a/java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ConvertFieldToAtomicIntention.java b/java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ConvertFieldToAtomicIntention.java index c47383832fae..ca7e89128d00 100644 --- a/java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ConvertFieldToAtomicIntention.java +++ b/java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ConvertFieldToAtomicIntention.java @@ -9,31 +9,21 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.psi.*; +import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.impl.AllowedApiFilterExtension; import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.search.searches.ReferencesSearch; -import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiUtil; -import com.intellij.psi.util.TypeConversionUtil; -import com.intellij.refactoring.typeMigration.TypeConversionDescriptor; -import com.intellij.refactoring.typeMigration.TypeEvaluator; -import com.intellij.refactoring.typeMigration.TypeMigrationReplacementUtil; -import com.intellij.refactoring.typeMigration.rules.AtomicConversionRule; -import com.intellij.refactoring.util.RefactoringUtil; +import com.intellij.refactoring.typeMigration.TypeMigrationVariableTypeFixProvider; 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; -import java.util.HashSet; import java.util.Map; -import java.util.Set; import java.util.concurrent.atomic.*; -import static com.intellij.psi.util.TypeConversionUtil.isBinaryOperatorApplicable; import static com.intellij.util.ObjectUtils.assertNotNull; /** @@ -102,145 +92,118 @@ public class ConvertFieldToAtomicIntention extends PsiElementBaseIntentionAction @Override public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException { - final PsiVariable psiVariable = getVariable(element); - LOG.assertTrue(psiVariable != null); + final PsiVariable var = getVariable(element); + LOG.assertTrue(var != null); - final Query refs = ReferencesSearch.search(psiVariable); + final PsiType fromType = var.getType(); + PsiClassType toType = getMigrationTargetType(project, element, fromType); + if (toType == null) return; - final Set elements = new HashSet<>(); - elements.add(element); - for (PsiReference reference : refs) { - elements.add(reference.getElement()); + if (!FileModificationService.getInstance().preparePsiElementsForWrite(var)) return; + addExplicitInitializer(var); + String toTypeCanonicalText = toType.getCanonicalText(); + TypeMigrationVariableTypeFixProvider.runTypeMigrationOnVariable(var, toType, editor, false, false); + postProcessVariable(var, toTypeCanonicalText); + } + + static void addExplicitInitializer(@NotNull PsiVariable var) { + PsiExpression currentInitializer = var.getInitializer(); + if (currentInitializer != null) return; + final PsiType type = var.getType(); + String initializerText = null; + if (PsiType.BOOLEAN.equals(type)) { + initializerText = "false"; } - if (!FileModificationService.getInstance().preparePsiElementsForWrite(elements)) return; + else if (type instanceof PsiPrimitiveType) { + initializerText = "0"; + } + if (initializerText != null) { + String finalInitializerText = initializerText; + WriteAction.run(() -> { + PsiExpression initializer = JavaPsiFacade.getElementFactory(var.getProject()).createExpressionFromText(finalInitializerText, var); + if (var instanceof PsiLocalVariable) { + ((PsiLocalVariable)var).setInitializer(initializer); + } + else if (var instanceof PsiField) { + ((PsiField)var).setInitializer(initializer); + } + }); + } + } - WriteAction.run(() -> { - psiVariable.normalizeDeclaration(); + static void postProcessVariable(@NotNull PsiVariable var, @NotNull String toType) { - 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 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 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)); - } + Project project = var.getProject(); + if (var instanceof PsiField || CodeStyleSettingsManager.getSettings(project).GENERATE_FINAL_LOCALS) { + PsiModifierList modifierList = assertNotNull(var.getModifierList()); + WriteAction.run(() -> { + if (var.getInitializer() == null) { + final PsiExpression newInitializer = JavaPsiFacade.getElementFactory(project).createExpressionFromText("new " + toType + "()", var); + if (var instanceof PsiLocalVariable) { + ((PsiLocalVariable)var).setInitializer(newInitializer); } + else if (var instanceof PsiField) { + ((PsiField)var).setInitializer(newInitializer); + } + JavaCodeStyleManager.getInstance(var.getProject()).shortenClassReferences(var.getInitializer()); } - 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()); - } + modifierList.setModifierProperty(PsiModifier.FINAL, true); + modifierList.setModifierProperty(PsiModifier.VOLATILE, false); - PsiElement replaced = assertNotNull(psiVariable.getTypeElement()).replace(factory.createTypeElement(toType)); - JavaCodeStyleManager.getInstance(project).shortenClassReferences(replaced); + JavaCodeStyleManager.getInstance(project).shortenClassReferences(var); + CodeStyleManager.getInstance(project).reformat(var); + }); + } + } - 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); - } + @Nullable + private PsiClassType getMigrationTargetType(@NotNull Project project, + @NotNull PsiElement element, + @NotNull PsiType fromType) { + JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project); + PsiElementFactory factory = psiFacade.getElementFactory(); + final String atomicQualifiedName = myFromToMap.get(fromType); + if (atomicQualifiedName != null) { + final PsiClass atomicClass = psiFacade.findClass(atomicQualifiedName, GlobalSearchScope.allScope(project)); + if (atomicClass == null) {//show warning + return null; } - catch (IncorrectOperationException e) { - LOG.error(e); + return 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 null; } - }); + final Map 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); + } + return factory.createType(atomicReferenceArrayClass, factory.createSubstitutor(substitutor)); + } + else { + final PsiClass atomicReferenceClass = psiFacade.findClass(AtomicReference.class.getName(), GlobalSearchScope.allScope(project)); + if (atomicReferenceClass == null) {//show warning + return null; + } + final Map 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); + } + return factory.createType(atomicReferenceClass, factory.createSubstitutor(substitutor)); + } } @Override public boolean startInWriteAction() { return false; } - - private static boolean isBinaryOpApplicable(@Nullable IElementType opSign, - @NotNull PsiExpression lExpr, - @Nullable PsiExpression rExpr, - @NotNull PsiElement varElement, - @NotNull PsiType migrationType) { - if (opSign == null || rExpr == null) return false; - PsiType lType = lExpr == varElement ? migrationType : lExpr.getType(); - PsiType rType = rExpr == varElement ? migrationType : rExpr.getType(); - return isBinaryOperatorApplicable(opSign, lType, rType, true); - } } diff --git a/java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ConvertFieldToThreadLocalIntention.java b/java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ConvertFieldToThreadLocalIntention.java index 0e03d91dd617..fcaf9defa8c4 100644 --- a/java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ConvertFieldToThreadLocalIntention.java +++ b/java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ConvertFieldToThreadLocalIntention.java @@ -4,32 +4,22 @@ import com.intellij.codeInsight.FileModificationService; import com.intellij.codeInsight.intention.LowPriorityAction; import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction; import com.intellij.lang.java.JavaLanguage; -import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.psi.*; -import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.impl.AllowedApiFilterExtension; -import com.intellij.psi.impl.PsiDiamondTypeUtil; import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; -import com.intellij.refactoring.typeMigration.*; -import com.intellij.refactoring.typeMigration.rules.ThreadLocalConversionRule; -import com.intellij.refactoring.util.RefactoringUtil; +import com.intellij.refactoring.typeMigration.TypeMigrationVariableTypeFixProvider; 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; -import java.util.HashSet; import java.util.Map; -import java.util.Set; - -import static com.intellij.util.ObjectUtils.assertNotNull; public class ConvertFieldToThreadLocalIntention extends PsiElementBaseIntentionAction implements LowPriorityAction { private static final Logger LOG = Logger.getInstance(ConvertFieldToThreadLocalIntention.class); @@ -66,101 +56,39 @@ public class ConvertFieldToThreadLocalIntention extends PsiElementBaseIntentionA public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException { final PsiField psiField = PsiTreeUtil.getParentOfType(element, PsiField.class); LOG.assertTrue(psiField != null); - final Query refs = ReferencesSearch.search(psiField); - final Set elements = new HashSet<>(); - elements.add(element); - for (PsiReference reference : refs) { - elements.add(reference.getElement()); - } - if (!FileModificationService.getInstance().preparePsiElementsForWrite(elements)) return; - WriteAction.run(() -> { - psiField.normalizeDeclaration(); + final PsiType fromType = psiField.getType(); - final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project); - final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); - final PsiType fromType = psiField.getType(); + final PsiClassType toType = getMigrationTargetType(fromType, project, element); + if (toType == null) return; - final PsiClass threadLocalClass = psiFacade.findClass(ThreadLocal.class.getName(), GlobalSearchScope.allScope(project)); - if (threadLocalClass == null) {//show warning - return; - } - final Map substitutor = ContainerUtil.newHashMap(); - final PsiTypeParameter[] typeParameters = threadLocalClass.getTypeParameters(); - if (typeParameters.length == 1) { - PsiType type = fromType; - if (fromType instanceof PsiPrimitiveType) type = ((PsiPrimitiveType)fromType).getBoxedType(element); - substitutor.put(typeParameters[0], type); - } - final PsiClassType toType = factory.createType(threadLocalClass, factory.createSubstitutor(substitutor)); - - try { - final TypeMigrationRules rules = new TypeMigrationRules(); - rules.setBoundScope(GlobalSearchScope.fileScope(element.getContainingFile())); - final TypeMigrationLabeler labeler = new TypeMigrationLabeler(rules, toType); - labeler.getMigratedUsages(false, psiField); - for (PsiReference reference : refs) { - PsiElement psiElement = reference.getElement(); - if (psiElement instanceof PsiExpression) { - final PsiElement parent = psiElement.getParent(); - if (parent instanceof PsiExpression && !(parent instanceof PsiReferenceExpression || parent instanceof PsiPolyadicExpression)) { - psiElement = parent; - } - final TypeConversionDescriptor conversion = - ThreadLocalConversionRule.findDirectConversion(psiElement, toType, fromType, labeler); - if (conversion != null) { - TypeMigrationReplacementUtil.replaceExpression((PsiExpression)psiElement, project, conversion, new TypeEvaluator(null, null)); - } - } - } - - PsiExpression initializer = psiField.getInitializer(); - - if (initializer == null && - !psiField.hasModifierProperty(PsiModifier.FINAL)) { - final PsiType type = psiField.getType(); - String initializerText = null; - if (PsiType.BOOLEAN.equals(type)) { - initializerText = "false"; - } - else if (type instanceof PsiPrimitiveType) { - initializerText = "0"; - } - if (initializerText != null) { - psiField.setInitializer(factory.createExpressionFromText(initializerText, psiField)); - initializer = psiField.getInitializer(); - } - } - if (initializer != null) { - if (initializer instanceof PsiArrayInitializerExpression) { - PsiExpression normalizedExpr = - RefactoringUtil.createNewExpressionFromArrayInitializer((PsiArrayInitializerExpression)initializer, psiField.getType()); - initializer = (PsiExpression)initializer.replace(normalizedExpr); - } - final TypeConversionDescriptor conversion = ThreadLocalConversionRule.wrapWithNewExpression(toType, fromType, initializer); - TypeMigrationReplacementUtil.replaceExpression(initializer, project, conversion, new TypeEvaluator(null, null)); - CodeStyleManager.getInstance(project).reformat(psiField); - } - else if (!assertNotNull(psiField.getModifierList()).hasModifierProperty(PsiModifier.FINAL)) { - final String text = "new " + PsiDiamondTypeUtil.getCollapsedType(toType, psiField) + "()"; - final PsiExpression newInitializer = factory.createExpressionFromText(text, psiField); - psiField.setInitializer(newInitializer); - } - - assertNotNull(psiField.getTypeElement()).replace(factory.createTypeElement(toType)); - - final PsiModifierList modifierList = assertNotNull(psiField.getModifierList()); - modifierList.setModifierProperty(PsiModifier.FINAL, true); - modifierList.setModifierProperty(PsiModifier.VOLATILE, false); - } - catch (IncorrectOperationException e) { - LOG.error(e); - } - }); + if (!FileModificationService.getInstance().preparePsiElementsForWrite(psiField)) return; + ConvertFieldToAtomicIntention.addExplicitInitializer(psiField); + String toTypeCanonicalText = toType.getCanonicalText(); + TypeMigrationVariableTypeFixProvider.runTypeMigrationOnVariable(psiField, toType, editor, false, false); + ConvertFieldToAtomicIntention.postProcessVariable(psiField, toTypeCanonicalText); } @Override public boolean startInWriteAction() { return false; } + + @Nullable + private static PsiClassType getMigrationTargetType(@NotNull PsiType fromType, @NotNull Project project, @NotNull PsiElement context) { + JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project); + final PsiClass threadLocalClass = psiFacade.findClass(ThreadLocal.class.getName(), GlobalSearchScope.allScope(project)); + if (threadLocalClass == null) {//show warning + return null; + } + final Map substitutor = ContainerUtil.newHashMap(); + final PsiTypeParameter[] typeParameters = threadLocalClass.getTypeParameters(); + if (typeParameters.length == 1) { + PsiType type = fromType; + if (fromType instanceof PsiPrimitiveType) type = ((PsiPrimitiveType)fromType).getBoxedType(context); + substitutor.put(typeParameters[0], type); + } + PsiElementFactory factory = psiFacade.getElementFactory(); + return factory.createType(threadLocalClass, factory.createSubstitutor(substitutor)); + } } diff --git a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/AtomicConversionRule.java b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/AtomicConversionRule.java index 2acf82df2ac3..2ba1e0fa7461 100644 --- a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/AtomicConversionRule.java +++ b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/AtomicConversionRule.java @@ -87,6 +87,9 @@ public class AtomicConversionRule extends TypeConversionRule { final PsiClass toTypeClass = PsiUtil.resolveClassInType(to); LOG.assertTrue(toTypeClass != null); final String qualifiedName = toTypeClass.getQualifiedName(); + if (context instanceof PsiParenthesizedExpression) { + context = ParenthesesUtils.stripParentheses((PsiExpression)context); + } if (qualifiedName != null) { if (qualifiedName.equals(AtomicInteger.class.getName()) || qualifiedName.equals(AtomicLong.class.getName())) { @@ -271,12 +274,33 @@ public class AtomicConversionRule extends TypeConversionRule { final PsiClassType boxedFromType = ((PsiPrimitiveType)from).getBoxedType(atomicClass); LOG.assertTrue(boxedFromType != null); if (!TypeConversionUtil.isAssignable(initial, boxedFromType)) { - return new TypeConversionDescriptor("$val$", "new " + typeText + "((" + unboxedInitialType.getCanonicalText() + ")$val$)", expression); + return new ArrayInitializerAwareConversionDescriptor("$val$", "new " + typeText + "((" + unboxedInitialType.getCanonicalText() + ")$val$)", expression); } } } } - return new TypeConversionDescriptor("$val$", "new " + typeText + "($val$)", expression); + return new ArrayInitializerAwareConversionDescriptor("$val$", "new " + typeText + "($val$)", expression); + } + + static class ArrayInitializerAwareConversionDescriptor extends TypeConversionDescriptor { + public ArrayInitializerAwareConversionDescriptor(String stringToReplace, + String replaceByString, + PsiExpression expression) { + super(stringToReplace, replaceByString, expression); + } + + @NotNull + @Override + protected PsiExpression adjustExpressionBeforeReplacement(@NotNull PsiExpression expression) { + if (expression instanceof PsiArrayInitializerExpression) { + PsiElementFactory elementFactory = JavaPsiFacade.getInstance(expression.getProject()).getElementFactory(); + return (PsiExpression)expression.replace(elementFactory.createExpressionFromText("new " + + TypeConversionUtil.erasure(expression.getType()).getCanonicalText() + + expression.getText(), + expression)); + } + return expression; + } } @Nullable @@ -286,6 +310,9 @@ public class AtomicConversionRule extends TypeConversionRule { final PsiElement parent = context.getParent(); final PsiElement parentParent = parent.getParent(); + if (context instanceof PsiReferenceExpression && isReferenceToLengthField((PsiReferenceExpression)context)) { + return new TypeConversionDescriptor("$qualifier$.length", "$qualifier$.length()"); + } if (parent instanceof PsiAssignmentExpression) { final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression)parent; final IElementType operationSign = assignmentExpression.getOperationTokenType(); @@ -344,9 +371,6 @@ public class AtomicConversionRule extends TypeConversionRule { if (context instanceof PsiArrayAccessExpression) { return new TypeConversionDescriptor("$qualifier$[$idx$]", "$qualifier$.get($idx$)", (PsiExpression)context); } - if (parent instanceof PsiReferenceExpression && isReferenceToLengthField((PsiReferenceExpression)parent)) { - return new TypeConversionDescriptor("$qualifier$.length", "$qualifier$.length()", (PsiExpression)parent); - } return null; } diff --git a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/ThreadLocalConversionRule.java b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/ThreadLocalConversionRule.java index bf7e2cc746aa..9831f8c51290 100644 --- a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/ThreadLocalConversionRule.java +++ b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/ThreadLocalConversionRule.java @@ -91,6 +91,10 @@ public class ThreadLocalConversionRule extends TypeConversionRule { return new TypeConversionDescriptor("$qualifier$" + sign + "$val$", toPrimitive("$qualifier$.get()", from, context) + " " + sign + " $val$"); } + if (parent instanceof PsiVariable && ((PsiVariable)parent).getInitializer() == context) { + return wrapWithNewExpression(to, from, (PsiExpression)context); + } + if (parent instanceof PsiExpressionStatement) { if (context instanceof PsiPostfixExpression) { final PsiPostfixExpression postfixExpression = (PsiPostfixExpression)context; @@ -169,12 +173,12 @@ public class ThreadLocalConversionRule extends TypeConversionRule { PsiExpression initializer, String boxedTypeName) { if (PsiUtil.isLanguageLevel8OrHigher(initializer)) { - return "java.lang.ThreadLocal.withInitial(() -> " + initializer.getText() + ")"; + return "java.lang.ThreadLocal.withInitial(() -> $qualifier$)"; } return "new " + to.getCanonicalText() + "() {\n" + - "@Override \n" + + "@Override\n" + "protected " + boxedTypeName + " initialValue() {\n" + @@ -183,9 +187,7 @@ public class ThreadLocalConversionRule extends TypeConversionRule { ? initializer.getText() : (from instanceof PsiPrimitiveType ? "new " + ((PsiPrimitiveType)from).getBoxedTypeName() + - "(" + - initializer.getText() + - ")" : initializer.getText())) + + "($qualifier$)" : "$qualifier$")) + ";\n" + "}\n" + "}"; @@ -242,7 +244,7 @@ public class ThreadLocalConversionRule extends TypeConversionRule { return toBoxed(arg, from, context); } - private static class WrappingWithInnerClassOrLambdaDescriptor extends TypeConversionDescriptor { + private static class WrappingWithInnerClassOrLambdaDescriptor extends AtomicConversionRule.ArrayInitializerAwareConversionDescriptor { private final List myVariablesToMakeFinal; private WrappingWithInnerClassOrLambdaDescriptor(@NonNls final String stringToReplace, diff --git a/java/typeMigration/test/com/intellij/codeInsight/ConvertToAtomicIntentionTest.java b/java/typeMigration/test/com/intellij/codeInsight/ConvertToAtomicIntentionTest.java index d4de1aa249ac..88b67ebaf3d7 100644 --- a/java/typeMigration/test/com/intellij/codeInsight/ConvertToAtomicIntentionTest.java +++ b/java/typeMigration/test/com/intellij/codeInsight/ConvertToAtomicIntentionTest.java @@ -1,6 +1,7 @@ package com.intellij.codeInsight; import com.intellij.codeInsight.daemon.quickFix.LightQuickFixParameterizedTestCase; +import com.intellij.refactoring.typeMigration.TypeMigrationProcessor; import com.intellij.testFramework.PlatformTestUtil; import org.jetbrains.annotations.NotNull; @@ -24,6 +25,18 @@ public class ConvertToAtomicIntentionTest extends LightQuickFixParameterizedTest return PlatformTestUtil.getCommunityPath() + "/java/typeMigration/testData"; } + @Override + public void setUp() throws Exception { + super.setUp(); + TypeMigrationProcessor.ourSkipFailedConversionInTestMode = true; + } + + @Override + public void tearDown() throws Exception { + TypeMigrationProcessor.ourSkipFailedConversionInTestMode = false; + super.tearDown(); + } + public void test() throws Exception { doAllTests(); } diff --git a/java/typeMigration/test/com/intellij/refactoring/ChangeTypeSignatureTest.java b/java/typeMigration/test/com/intellij/refactoring/ChangeTypeSignatureTest.java index 1f05c9b3bc6b..c01576fd5dab 100644 --- a/java/typeMigration/test/com/intellij/refactoring/ChangeTypeSignatureTest.java +++ b/java/typeMigration/test/com/intellij/refactoring/ChangeTypeSignatureTest.java @@ -52,7 +52,8 @@ public class ChangeTypeSignatureTest extends LightCodeInsightTestCase { new TypeMigrationProcessor(getProject(), new PsiElement[]{parameterList}, Functions.constant(PsiSubstitutor.EMPTY.put(superClass.getTypeParameters()[0], migrationType).substitute(new PsiImmediateClassType(superClass, PsiSubstitutor.EMPTY))), - rules).run(); + rules, + true).run(); if (success) { checkResultByFile(dataPath + getTestName(false) + ".java.after"); } else { diff --git a/java/typeMigration/test/com/intellij/refactoring/TypeMigrationTestBase.java b/java/typeMigration/test/com/intellij/refactoring/TypeMigrationTestBase.java index 36dc0634ddfa..9571f6fac611 100644 --- a/java/typeMigration/test/com/intellij/refactoring/TypeMigrationTestBase.java +++ b/java/typeMigration/test/com/intellij/refactoring/TypeMigrationTestBase.java @@ -229,7 +229,7 @@ public abstract class TypeMigrationTestBase extends MultiFileTestCase { private static class TestTypeMigrationProcessor extends TypeMigrationProcessor { public TestTypeMigrationProcessor(final Project project, final PsiElement[] roots, final PsiType migrationType, final TypeMigrationRules rules) { - super(project, roots, Functions.constant(migrationType), rules); + super(project, roots, Functions.constant(migrationType), rules, true); } } } \ No newline at end of file diff --git a/java/typeMigration/testData/intentions/atomic/after1.java b/java/typeMigration/testData/intentions/atomic/after1.java index 853f715fd8c4..ef8057593d95 100644 --- a/java/typeMigration/testData/intentions/atomic/after1.java +++ b/java/typeMigration/testData/intentions/atomic/after1.java @@ -2,7 +2,7 @@ import java.util.concurrent.atomic.AtomicIntegerArray; // "Convert to atomic" "true" class Test { - final AtomicIntegerArray field= new AtomicIntegerArray(foo()); + final AtomicIntegerArray field = new AtomicIntegerArray(foo()); int[] foo() { return null; } diff --git a/java/typeMigration/testData/intentions/atomic/after10.java b/java/typeMigration/testData/intentions/atomic/after10.java index 685e3fb710e2..34569c8e2114 100644 --- a/java/typeMigration/testData/intentions/atomic/after10.java +++ b/java/typeMigration/testData/intentions/atomic/after10.java @@ -2,7 +2,7 @@ import java.util.concurrent.atomic.AtomicInteger; // "Convert to atomic" "true" class Test { - final AtomicInteger o = new AtomicInteger(0); + final AtomicInteger o = new AtomicInteger(0); void foo() { boolean b = this.o.get() == 1; diff --git a/java/typeMigration/testData/intentions/atomic/after13.java b/java/typeMigration/testData/intentions/atomic/after13.java index dea58d02e88c..c92136bb5030 100644 --- a/java/typeMigration/testData/intentions/atomic/after13.java +++ b/java/typeMigration/testData/intentions/atomic/after13.java @@ -2,5 +2,5 @@ import java.util.concurrent.atomic.AtomicInteger; // "Convert to atomic" "true" class Test { - final AtomicInteger i = new AtomicInteger(0); + final AtomicInteger i = new AtomicInteger(0); } \ No newline at end of file diff --git a/java/typeMigration/testData/intentions/atomic/after14.java b/java/typeMigration/testData/intentions/atomic/after14.java index 6109d4106e9b..79e0560becad 100644 --- a/java/typeMigration/testData/intentions/atomic/after14.java +++ b/java/typeMigration/testData/intentions/atomic/after14.java @@ -2,7 +2,7 @@ import java.util.concurrent.atomic.AtomicLong; // "Convert to atomic" "true" class T { - private final AtomicLong l = new AtomicLong(10L); + private final AtomicLong l = new AtomicLong(10L); public synchronized void update(long m) { l.set(m); diff --git a/java/typeMigration/testData/intentions/atomic/after2.java b/java/typeMigration/testData/intentions/atomic/after2.java index 2c2ad94beeb0..2c71c0825534 100644 --- a/java/typeMigration/testData/intentions/atomic/after2.java +++ b/java/typeMigration/testData/intentions/atomic/after2.java @@ -2,7 +2,7 @@ import java.util.concurrent.atomic.AtomicReferenceArray; // "Convert to atomic" "true" class Test { - final AtomicReferenceArray field= new AtomicReferenceArray<>(foo()); + final AtomicReferenceArray field = new AtomicReferenceArray<>(foo()); Object[] foo() { return null; } diff --git a/java/typeMigration/testData/intentions/atomic/after3.java b/java/typeMigration/testData/intentions/atomic/after3.java index 505349d5dc36..7804ef5d08e6 100644 --- a/java/typeMigration/testData/intentions/atomic/after3.java +++ b/java/typeMigration/testData/intentions/atomic/after3.java @@ -2,6 +2,6 @@ import java.util.concurrent.atomic.AtomicIntegerArray; // "Convert to atomic" "true" class Test { - final AtomicIntegerArray field= new AtomicIntegerArray(new int[]{1}); + final AtomicIntegerArray field = new AtomicIntegerArray(new int[]{1}); } \ No newline at end of file diff --git a/java/typeMigration/testData/intentions/atomic/after4.java b/java/typeMigration/testData/intentions/atomic/after4.java index e268b2604404..9a46fadf087a 100644 --- a/java/typeMigration/testData/intentions/atomic/after4.java +++ b/java/typeMigration/testData/intentions/atomic/after4.java @@ -2,8 +2,8 @@ import java.util.concurrent.atomic.AtomicInteger; // "Convert to atomic" "true" class Test { - final AtomicInteger i = new AtomicInteger(0); + final AtomicInteger i = new AtomicInteger(0); int j = i.get() + 5; - String s = "i = " + i.get(); + String s = "i = " + i; } \ No newline at end of file diff --git a/java/typeMigration/testData/intentions/atomic/after5.java b/java/typeMigration/testData/intentions/atomic/after5.java index 82ff84c68e75..6bd1c2f36e89 100644 --- a/java/typeMigration/testData/intentions/atomic/after5.java +++ b/java/typeMigration/testData/intentions/atomic/after5.java @@ -2,8 +2,8 @@ import java.util.concurrent.atomic.AtomicInteger; // "Convert to atomic" "true" class Test { - final AtomicInteger i = new AtomicInteger(0 + 8); + final AtomicInteger i = new AtomicInteger(0 + 8); int j = i.get() + 5; - String s = "i = " + i.get(); + String s = "i = " + i; } \ No newline at end of file diff --git a/java/typeMigration/testData/intentions/atomic/after6.java b/java/typeMigration/testData/intentions/atomic/after6.java index f0120300e0f9..c5c018c7f17f 100644 --- a/java/typeMigration/testData/intentions/atomic/after6.java +++ b/java/typeMigration/testData/intentions/atomic/after6.java @@ -2,5 +2,5 @@ import java.util.concurrent.atomic.AtomicIntegerArray; // "Convert to atomic" "true" class Test { - final AtomicIntegerArray i = new AtomicIntegerArray(new int[0]); + final AtomicIntegerArray i = new AtomicIntegerArray(new int[0]); } \ No newline at end of file diff --git a/java/typeMigration/testData/intentions/atomic/after7.java b/java/typeMigration/testData/intentions/atomic/after7.java index 19336f0bc61b..7231e3c259ad 100644 --- a/java/typeMigration/testData/intentions/atomic/after7.java +++ b/java/typeMigration/testData/intentions/atomic/after7.java @@ -2,10 +2,10 @@ import java.util.concurrent.atomic.AtomicInteger; // "Convert to atomic" "true" class Test { - final AtomicInteger o = new AtomicInteger(0); + final AtomicInteger o = new AtomicInteger(0); int j = o.get(); void foo() { - while ((o = j) != 0) {} + while ((o.set(j)) != 0) {} } } \ No newline at end of file diff --git a/java/typeMigration/testData/intentions/atomic/after8.java b/java/typeMigration/testData/intentions/atomic/after8.java index bdfbd5b03a4d..7231e3c259ad 100644 --- a/java/typeMigration/testData/intentions/atomic/after8.java +++ b/java/typeMigration/testData/intentions/atomic/after8.java @@ -2,10 +2,10 @@ import java.util.concurrent.atomic.AtomicInteger; // "Convert to atomic" "true" class Test { - final AtomicInteger o = new AtomicInteger(); + final AtomicInteger o = new AtomicInteger(0); int j = o.get(); void foo() { - while ((o = j) != 0) {} + while ((o.set(j)) != 0) {} } } \ No newline at end of file diff --git a/java/typeMigration/testData/intentions/atomic/after9.java b/java/typeMigration/testData/intentions/atomic/after9.java index c462a10961d4..c31f7835f36e 100644 --- a/java/typeMigration/testData/intentions/atomic/after9.java +++ b/java/typeMigration/testData/intentions/atomic/after9.java @@ -2,14 +2,14 @@ import java.util.concurrent.atomic.AtomicInteger; // "Convert to atomic" "true" class Test { - final AtomicInteger o; + final AtomicInteger o = new AtomicInteger(0); int j = o.get(); Test(int o) { - this.o = new AtomicInteger(o); + this.o.set(o); } void foo() { - while ((o = j) != 0) {} + while ((o.set(j)) != 0) {} } } \ No newline at end of file diff --git a/java/typeMigration/testData/intentions/atomic/afterArrayInitializer.java b/java/typeMigration/testData/intentions/atomic/afterArrayInitializer.java index f2b51fa36440..ee554f41ab0c 100644 --- a/java/typeMigration/testData/intentions/atomic/afterArrayInitializer.java +++ b/java/typeMigration/testData/intentions/atomic/afterArrayInitializer.java @@ -2,5 +2,5 @@ import java.util.concurrent.atomic.AtomicReferenceArray; // "Convert to atomic" "true" class Test { - final AtomicReferenceArray field= new AtomicReferenceArray<>(new String[]{}); + final AtomicReferenceArray field = new AtomicReferenceArray<>(new String[]{}); } \ No newline at end of file diff --git a/java/typeMigration/testData/intentions/atomic/afterAssignmentOp.java b/java/typeMigration/testData/intentions/atomic/afterAssignmentOp.java index 0bb7d49f37e1..6aac0f12d512 100644 --- a/java/typeMigration/testData/intentions/atomic/afterAssignmentOp.java +++ b/java/typeMigration/testData/intentions/atomic/afterAssignmentOp.java @@ -2,7 +2,7 @@ import java.util.concurrent.atomic.AtomicLong; // "Convert to atomic" "true" class A { - final AtomicLong x = new AtomicLong(0); + final AtomicLong x = new AtomicLong(0); public void testAtomicLong() { x.getAndIncrement(); diff --git a/java/typeMigration/testData/intentions/atomic/afterAtomicArrayLength.java b/java/typeMigration/testData/intentions/atomic/afterAtomicArrayLength.java index 76bd5940cb3a..5129b22b4809 100644 --- a/java/typeMigration/testData/intentions/atomic/afterAtomicArrayLength.java +++ b/java/typeMigration/testData/intentions/atomic/afterAtomicArrayLength.java @@ -2,7 +2,7 @@ import java.util.concurrent.atomic.AtomicIntegerArray; // "Convert to atomic" "true" class Test { - final AtomicIntegerArray ii = new AtomicIntegerArray(new int[12]); + final AtomicIntegerArray ii = new AtomicIntegerArray(new int[12]); void m() { int k = ii.length(); diff --git a/java/typeMigration/testData/intentions/atomic/afterExcl.java b/java/typeMigration/testData/intentions/atomic/afterExcl.java index 72f91198ce3d..48c48c88ba72 100644 --- a/java/typeMigration/testData/intentions/atomic/afterExcl.java +++ b/java/typeMigration/testData/intentions/atomic/afterExcl.java @@ -2,7 +2,7 @@ import java.util.concurrent.atomic.AtomicBoolean; // "Convert to atomic" "true" class Test { - final AtomicBoolean field= new AtomicBoolean(false); + final AtomicBoolean field = new AtomicBoolean(false); { boolean b = !field.get(); } diff --git a/java/typeMigration/testData/intentions/atomic/afterNormalize.java b/java/typeMigration/testData/intentions/atomic/afterNormalize.java index c454d5787206..1c19518830b5 100644 --- a/java/typeMigration/testData/intentions/atomic/afterNormalize.java +++ b/java/typeMigration/testData/intentions/atomic/afterNormalize.java @@ -2,7 +2,7 @@ import java.util.concurrent.atomic.AtomicReference; // "Convert to atomic" "true" class X { - private final AtomicReference s = new AtomicReference<>(""); + private final AtomicReference s = new AtomicReference<>(""); private String t; private String u; } \ No newline at end of file diff --git a/java/typeMigration/testData/intentions/threadLocal/after6.java b/java/typeMigration/testData/intentions/threadLocal/after6.java index d153a6579061..4ac6c8bf78e1 100644 --- a/java/typeMigration/testData/intentions/threadLocal/after6.java +++ b/java/typeMigration/testData/intentions/threadLocal/after6.java @@ -1,7 +1,7 @@ // "Convert to ThreadLocal" "true" class Test { - static final ThreadLocal field; + static final ThreadLocal field = new ThreadLocal(); static { - field = ThreadLocal.withInitial(() -> new Integer(0)); + field.set(new Integer(0)); } } \ No newline at end of file diff --git a/java/typeMigration/testData/intentions/threadLocal/afterFieldAssignmentFromNonFinalParameter.java b/java/typeMigration/testData/intentions/threadLocal/afterFieldAssignmentFromNonFinalParameter.java index 654691a7f2c9..f792c3c1e7bd 100644 --- a/java/typeMigration/testData/intentions/threadLocal/afterFieldAssignmentFromNonFinalParameter.java +++ b/java/typeMigration/testData/intentions/threadLocal/afterFieldAssignmentFromNonFinalParameter.java @@ -1,12 +1,11 @@ // "Convert to ThreadLocal" "true" class Main { - private final ThreadLocal property; + private final ThreadLocal property = ThreadLocal.withInitial(() -> false); Main3(boolean property) { if (property) { property = false; } - boolean finalProperty = property; - this.property = ThreadLocal.withInitial(() -> finalProperty); + this.property.set(property); } } \ No newline at end of file diff --git a/java/typeMigration/testData/intentions/threadLocal/afterFinalField.java b/java/typeMigration/testData/intentions/threadLocal/afterFinalField.java index da8f5235f329..172cae3957a0 100644 --- a/java/typeMigration/testData/intentions/threadLocal/afterFinalField.java +++ b/java/typeMigration/testData/intentions/threadLocal/afterFinalField.java @@ -1,8 +1,8 @@ // "Convert to ThreadLocal" "true" class Foo { - private final ThreadLocal property; + private final ThreadLocal property = ThreadLocal.withInitial(() -> false); Foo(boolean property) { - this.property = ThreadLocal.withInitial(() -> property); + this.property.set(property); } } \ No newline at end of file diff --git a/java/typeMigration/testData/intentions/threadLocal6/afterJava6.java b/java/typeMigration/testData/intentions/threadLocal6/afterJava6.java index 77bd711defff..f116d3848f33 100644 --- a/java/typeMigration/testData/intentions/threadLocal6/afterJava6.java +++ b/java/typeMigration/testData/intentions/threadLocal6/afterJava6.java @@ -1,13 +1,13 @@ // "Convert to ThreadLocal" "true" class Main { - private final ThreadLocal property; - - Main3(final boolean property) { - this.property = new ThreadLocal() { + private final ThreadLocal property = new ThreadLocal() { @Override protected Boolean initialValue() { - return property; + return false; } }; + + Main3(boolean property) { + this.property.set(property); } } \ No newline at end of file diff --git a/java/typeMigration/testData/refactoring/typeMigrationByAtomic/directString/after/Test.items b/java/typeMigration/testData/refactoring/typeMigrationByAtomic/directString/after/Test.items index 0d306b0b4747..0c9576812898 100644 --- a/java/typeMigration/testData/refactoring/typeMigrationByAtomic/directString/after/Test.items +++ b/java/typeMigration/testData/refactoring/typeMigrationByAtomic/directString/after/Test.items @@ -6,6 +6,7 @@ PsiReferenceExpression:s : java.util.concurrent.atomic.AtomicReference new java.util.concurrent.atomic.AtomicReference($val$) $val$ s -> $qualifier$.get() $qualifier$ s +s -> $qualifier$.get() $qualifier$ s New expression type changes: Fails: diff --git a/java/typeMigration/testData/refactoring/typeMigrationByAtomic/directString/after/Test.java b/java/typeMigration/testData/refactoring/typeMigrationByAtomic/directString/after/Test.java index cb32e0ba130b..c9b39344fce4 100644 --- a/java/typeMigration/testData/refactoring/typeMigrationByAtomic/directString/after/Test.java +++ b/java/typeMigration/testData/refactoring/typeMigrationByAtomic/directString/after/Test.java @@ -4,7 +4,7 @@ class Test { AtomicReference s = new AtomicReference(""); void foo() { - if (s == null) { + if (s.get() == null) { System.out.println(s.get()); } } diff --git a/java/typeMigration/testData/refactoring/typeMigrationByThreadLocal/directString/after/Test.items b/java/typeMigration/testData/refactoring/typeMigrationByThreadLocal/directString/after/Test.items index 29d4312a8580..bf665487b0c2 100644 --- a/java/typeMigration/testData/refactoring/typeMigrationByThreadLocal/directString/after/Test.items +++ b/java/typeMigration/testData/refactoring/typeMigrationByThreadLocal/directString/after/Test.items @@ -4,8 +4,14 @@ PsiReferenceExpression:myS : java.lang.ThreadLocal PsiReferenceExpression:myS : java.lang.ThreadLocal Conversions: +"" -> new java.lang.ThreadLocal() { +@Override +protected java.lang.String initialValue() { + return ""; +} +} $qualifier$ "" +myS -> $qualifier$.get() $qualifier$ myS myS -> $qualifier$.get() $qualifier$ myS New expression type changes: Fails: -""->java.lang.ThreadLocal diff --git a/java/typeMigration/testData/refactoring/typeMigrationByThreadLocal/directString/after/Test.java b/java/typeMigration/testData/refactoring/typeMigrationByThreadLocal/directString/after/Test.java index 949869096327..3e800d3fcd11 100644 --- a/java/typeMigration/testData/refactoring/typeMigrationByThreadLocal/directString/after/Test.java +++ b/java/typeMigration/testData/refactoring/typeMigrationByThreadLocal/directString/after/Test.java @@ -1,8 +1,13 @@ class Test { - ThreadLocal myS = ""; + ThreadLocal myS = new ThreadLocal() { + @Override + protected String initialValue() { + return ""; + } + }; void foo() { - if (myS == null) { + if (myS.get() == null) { System.out.println(myS.get()); } }