diff options
Diffstat (limited to 'java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ConvertFieldToThreadLocalIntention.java')
-rw-r--r-- | java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ConvertFieldToThreadLocalIntention.java | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ConvertFieldToThreadLocalIntention.java b/java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ConvertFieldToThreadLocalIntention.java new file mode 100644 index 000000000000..e01aaadae7d8 --- /dev/null +++ b/java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ConvertFieldToThreadLocalIntention.java @@ -0,0 +1,145 @@ +/* + * User: anna + * Date: 26-Aug-2009 + */ +package com.intellij.refactoring.typeMigration.intentions; + +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.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.TypeConversionDescriptor; +import com.intellij.refactoring.typeMigration.TypeMigrationLabeler; +import com.intellij.refactoring.typeMigration.TypeMigrationReplacementUtil; +import com.intellij.refactoring.typeMigration.TypeMigrationRules; +import com.intellij.refactoring.typeMigration.rules.ThreadLocalConversionRule; +import com.intellij.util.IncorrectOperationException; +import com.intellij.util.Query; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; + +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.getName()); + + @NotNull + @Override + public String getText() { + return "Convert to ThreadLocal"; + } + + @NotNull + @Override + public String getFamilyName() { + return getText(); + } + + @Override + public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) { + if (!(element instanceof PsiIdentifier)) return false; + final PsiField psiField = PsiTreeUtil.getParentOfType(element, PsiField.class); + if (psiField == null) return false; + if (psiField.getLanguage() != JavaLanguage.INSTANCE) return false; + if (psiField.getTypeElement() == null) return false; + final PsiType fieldType = psiField.getType(); + final PsiClass fieldTypeClass = PsiUtil.resolveClassInType(fieldType); + if (fieldType instanceof PsiPrimitiveType || fieldType instanceof PsiArrayType) return true; + return fieldTypeClass != null && !Comparing.strEqual(fieldTypeClass.getQualifiedName(), ThreadLocal.class.getName()) + && AllowedApiFilterExtension.isClassAllowed(ThreadLocal.class.getName(), element); + } + + @Override + 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<PsiElement>(); + elements.add(element); + for (PsiReference reference : refs) { + elements.add(reference.getElement()); + } + if (!FileModificationService.getInstance().preparePsiElementsForWrite(elements)) return; + + final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project); + final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); + final PsiType fromType = psiField.getType(); + + 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(fromType); + rules.setMigrationRootType(toType); + rules.setBoundScope(GlobalSearchScope.fileScope(element.getContainingFile())); + final TypeMigrationLabeler labeler = new TypeMigrationLabeler(rules); + 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); + } + } + } + + final PsiExpression initializer = psiField.getInitializer(); + if (initializer != null) { + final TypeConversionDescriptor conversion = ThreadLocalConversionRule.wrapWithNewExpression(toType, fromType, initializer); + TypeMigrationReplacementUtil.replaceExpression(initializer, project, conversion); + 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); + } + } + + @Override + public boolean startInWriteAction() { + return true; + } +} |