mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
type migration: convert to atomic / convert to thread local should use refactoring instead of manual conversion
This commit is contained in:
+1
-1
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
+10
-3
@@ -74,6 +74,7 @@ public class TypeMigrationLabeler {
|
||||
|
||||
private final TypeMigrationRules myRules;
|
||||
private final Function<PsiElement, PsiType> myMigrationRootTypeFunction;
|
||||
@Nullable private final Set<PsiElement> myAllowedRoots;
|
||||
private TypeEvaluator myTypeEvaluator;
|
||||
private final LinkedHashMap<PsiElement, Object> myConversions;
|
||||
private final Map<Pair<SmartPsiElementPointer<PsiExpression>, PsiType>, TypeMigrationUsageInfo> myFailedConversions;
|
||||
@@ -89,13 +90,16 @@ public class TypeMigrationLabeler {
|
||||
private final Map<Pair<TypeMigrationUsageInfo, TypeMigrationUsageInfo>, Set<PsiElement>> myRootUsagesTree = new HashMap<>();
|
||||
private final Set<TypeMigrationUsageInfo> 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<PsiElement, PsiType> migrationRootTypeFunction) {
|
||||
public TypeMigrationLabeler(TypeMigrationRules rules,
|
||||
Function<PsiElement, PsiType> 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;
|
||||
}
|
||||
|
||||
+22
-8
@@ -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<PsiElement, PsiType> myRootTypes;
|
||||
private final boolean myAllowDependentRoots;
|
||||
private final TypeMigrationRules myRules;
|
||||
private TypeMigrationLabeler myLabeler;
|
||||
|
||||
public TypeMigrationProcessor(final Project project, final PsiElement[] roots, final Function<PsiElement, PsiType> rootTypes, final TypeMigrationRules rules) {
|
||||
public TypeMigrationProcessor(final Project project,
|
||||
final PsiElement[] roots,
|
||||
final Function<PsiElement, PsiType> 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<PsiElement, PsiType> migrationTypeFunction,
|
||||
final boolean optimizeImports) {
|
||||
final Set<PsiFile> containingFiles = ContainerUtil.map2Set(roots, element -> element.getContainingFile());
|
||||
final TypeMigrationProcessor processor = new TypeMigrationProcessor(project, roots, migrationTypeFunction, rules) {
|
||||
final boolean optimizeImports,
|
||||
boolean allowDependentRoots) {
|
||||
final Set<PsiFile> 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<UsageInfo[]> 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";
|
||||
|
||||
+16
@@ -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<PsiType, PsiType> 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);
|
||||
}
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+6
-3
@@ -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,
|
||||
|
||||
+4
-3
@@ -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());
|
||||
}
|
||||
|
||||
+1
@@ -359,6 +359,7 @@ public class GuavaInspection extends BaseJavaLocalInspectionTool {
|
||||
rules,
|
||||
elements.toArray(new PsiElement[elements.size()]),
|
||||
createMigrationTypeFunction(elements, types),
|
||||
true,
|
||||
true);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+98
-135
@@ -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<PsiReference> refs = ReferencesSearch.search(psiVariable);
|
||||
final PsiType fromType = var.getType();
|
||||
PsiClassType toType = getMigrationTargetType(project, element, fromType);
|
||||
if (toType == null) return;
|
||||
|
||||
final Set<PsiElement> 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<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));
|
||||
}
|
||||
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<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);
|
||||
}
|
||||
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<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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
+28
-100
@@ -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<PsiReference> refs = ReferencesSearch.search(psiField);
|
||||
|
||||
final Set<PsiElement> 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<PsiTypeParameter, PsiType> 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<PsiTypeParameter, PsiType> 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));
|
||||
}
|
||||
}
|
||||
|
||||
+29
-5
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+8
-6
@@ -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<PsiVariable> myVariablesToMakeFinal;
|
||||
|
||||
private WrappingWithInnerClassOrLambdaDescriptor(@NonNls final String stringToReplace,
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -2,7 +2,7 @@ import java.util.concurrent.atomic.AtomicReferenceArray;
|
||||
|
||||
// "Convert to atomic" "true"
|
||||
class Test {
|
||||
final AtomicReferenceArray<Object> field= new AtomicReferenceArray<>(foo());
|
||||
final AtomicReferenceArray<Object> field = new AtomicReferenceArray<>(foo());
|
||||
Object[] foo() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -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});
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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]);
|
||||
}
|
||||
@@ -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) {}
|
||||
}
|
||||
}
|
||||
@@ -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) {}
|
||||
}
|
||||
}
|
||||
@@ -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) {}
|
||||
}
|
||||
}
|
||||
@@ -2,5 +2,5 @@ import java.util.concurrent.atomic.AtomicReferenceArray;
|
||||
|
||||
// "Convert to atomic" "true"
|
||||
class Test {
|
||||
final AtomicReferenceArray<String> field= new AtomicReferenceArray<>(new String[]{});
|
||||
final AtomicReferenceArray<String> field = new AtomicReferenceArray<>(new String[]{});
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
// "Convert to atomic" "true"
|
||||
class X {
|
||||
private final AtomicReference<String> s = new AtomicReference<>("");
|
||||
private final AtomicReference<String> s = new AtomicReference<>("");
|
||||
private String t;
|
||||
private String u;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// "Convert to ThreadLocal" "true"
|
||||
class Test {
|
||||
static final ThreadLocal<Integer> field;
|
||||
static final ThreadLocal<Integer> field = new ThreadLocal<Integer>();
|
||||
static {
|
||||
field = ThreadLocal.withInitial(() -> new Integer(0));
|
||||
field.set(new Integer(0));
|
||||
}
|
||||
}
|
||||
+2
-3
@@ -1,12 +1,11 @@
|
||||
// "Convert to ThreadLocal" "true"
|
||||
class Main {
|
||||
private final ThreadLocal<Boolean> property;
|
||||
private final ThreadLocal<Boolean> property = ThreadLocal.withInitial(() -> false);
|
||||
|
||||
Main3(boolean property) {
|
||||
if (property) {
|
||||
property = false;
|
||||
}
|
||||
boolean finalProperty = property;
|
||||
this.property = ThreadLocal.withInitial(() -> finalProperty);
|
||||
this.property.set(property);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
// "Convert to ThreadLocal" "true"
|
||||
class Foo {
|
||||
private final ThreadLocal<Boolean> property;
|
||||
private final ThreadLocal<Boolean> property = ThreadLocal.withInitial(() -> false);
|
||||
|
||||
Foo(boolean property) {
|
||||
this.property = ThreadLocal.withInitial(() -> property);
|
||||
this.property.set(property);
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
// "Convert to ThreadLocal" "true"
|
||||
class Main {
|
||||
private final ThreadLocal<Boolean> property;
|
||||
|
||||
Main3(final boolean property) {
|
||||
this.property = new ThreadLocal<Boolean>() {
|
||||
private final ThreadLocal<Boolean> property = new ThreadLocal<Boolean>() {
|
||||
@Override
|
||||
protected Boolean initialValue() {
|
||||
return property;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
Main3(boolean property) {
|
||||
this.property.set(property);
|
||||
}
|
||||
}
|
||||
+1
@@ -6,6 +6,7 @@ PsiReferenceExpression:s : java.util.concurrent.atomic.AtomicReference<java.lang
|
||||
Conversions:
|
||||
"" -> new java.util.concurrent.atomic.AtomicReference<java.lang.String>($val$) $val$
|
||||
s -> $qualifier$.get() $qualifier$ s
|
||||
s -> $qualifier$.get() $qualifier$ s
|
||||
|
||||
New expression type changes:
|
||||
Fails:
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ class Test {
|
||||
AtomicReference<String> s = new AtomicReference<String>("");
|
||||
|
||||
void foo() {
|
||||
if (s == null) {
|
||||
if (s.get() == null) {
|
||||
System.out.println(s.get());
|
||||
}
|
||||
}
|
||||
|
||||
+7
-1
@@ -4,8 +4,14 @@ PsiReferenceExpression:myS : java.lang.ThreadLocal<java.lang.String>
|
||||
PsiReferenceExpression:myS : java.lang.ThreadLocal<java.lang.String>
|
||||
|
||||
Conversions:
|
||||
"" -> new java.lang.ThreadLocal<java.lang.String>() {
|
||||
@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<java.lang.String>
|
||||
|
||||
+7
-2
@@ -1,8 +1,13 @@
|
||||
class Test {
|
||||
ThreadLocal<String> myS = "";
|
||||
ThreadLocal<String> myS = new ThreadLocal<String>() {
|
||||
@Override
|
||||
protected String initialValue() {
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
void foo() {
|
||||
if (myS == null) {
|
||||
if (myS.get() == null) {
|
||||
System.out.println(myS.get());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user