type migration: convert to atomic / convert to thread local should use refactoring instead of manual conversion

This commit is contained in:
Dmitry Batkovich
2017-06-08 17:03:20 +03:00
parent 3865e588a8
commit 2066338d72
42 changed files with 293 additions and 308 deletions
@@ -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) {
@@ -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;
}
@@ -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";
@@ -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);
}
@@ -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