100 | * Call this method before calling built-in {@link TypeMigrationProcessor#findUsages()} 101 | *
102 | */ 103 | public void clear() { 104 | failedUsages.clear(); 105 | updatedUsages.clear(); 106 | failedUsageToCorrespondingRule.clear(); 107 | usedRules.clear(); 108 | shouldCollect = true; 109 | } 110 | 111 | public boolean hasFailedTypeChanges() { 112 | return !failedUsages.isEmpty(); 113 | } 114 | 115 | public TypeEvaluator getTypeEvaluator() { 116 | return typeEvaluator; 117 | } 118 | 119 | public void setTypeEvaluator(TypeEvaluator typeEvaluator) { 120 | this.typeEvaluator = typeEvaluator; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /plugin/src/main/java/org/jetbrains/research/ddtm/ide/migration/structuralsearch/MyReplacer.java: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.ddtm.ide.migration.structuralsearch; 2 | 3 | import com.intellij.lang.Language; 4 | import com.intellij.openapi.fileTypes.LanguageFileType; 5 | import com.intellij.openapi.project.Project; 6 | import com.intellij.psi.PsiElement; 7 | import com.intellij.psi.PsiFile; 8 | import com.intellij.psi.PsiWhiteSpace; 9 | import com.intellij.psi.search.LocalSearchScope; 10 | import com.intellij.structuralsearch.MatchOptions; 11 | import com.intellij.structuralsearch.MatchResult; 12 | import com.intellij.structuralsearch.Matcher; 13 | import com.intellij.structuralsearch.PatternContextInfo; 14 | import com.intellij.structuralsearch.impl.matcher.MatcherImplUtil; 15 | import com.intellij.structuralsearch.impl.matcher.PatternTreeContext; 16 | import com.intellij.structuralsearch.plugin.replace.ReplaceOptions; 17 | import com.intellij.structuralsearch.plugin.replace.ReplacementInfo; 18 | import com.intellij.structuralsearch.plugin.replace.impl.Replacer; 19 | import com.intellij.structuralsearch.plugin.util.CollectingMatchResultSink; 20 | import com.intellij.util.IncorrectOperationException; 21 | import com.intellij.util.SmartList; 22 | import org.jetbrains.annotations.NotNull; 23 | 24 | import java.util.List; 25 | 26 | public class MyReplacer extends Replacer { 27 | public MyReplacer(@NotNull Project project, @NotNull ReplaceOptions options) { 28 | super(project, options); 29 | } 30 | 31 | public static String testReplace(String in, String what, String by, ReplaceOptions replaceOptions, Project project) { 32 | final LanguageFileType type = replaceOptions.getMatchOptions().getFileType(); 33 | return testReplace(in, what, by, replaceOptions, project, false, false, type, type.getLanguage()); 34 | } 35 | 36 | /** 37 | * Copied from {@link Replacer#testReplace(java.lang.String, java.lang.String, java.lang.String, com.intellij.structuralsearch.plugin.replace.ReplaceOptions, com.intellij.openapi.project.Project, boolean, boolean, com.intellij.openapi.fileTypes.LanguageFileType, com.intellij.lang.Language)}. 38 | * But it doesn't clears `searchCriteria` in the MatchOptions. 39 | */ 40 | public static String testReplace(String in, String what, String by, ReplaceOptions replaceOptions, Project project, boolean sourceIsFile, 41 | boolean createPhysicalFile, @NotNull LanguageFileType sourceFileType, @NotNull Language sourceDialect) { 42 | replaceOptions.setReplacement(by); 43 | 44 | final MatchOptions matchOptions = replaceOptions.getMatchOptions(); 45 | 46 | Matcher.validate(project, matchOptions); 47 | checkReplacementPattern(project, replaceOptions); 48 | 49 | final Replacer replacer = new Replacer(project, replaceOptions); 50 | final Matcher matcher = new Matcher(project, matchOptions); 51 | try { 52 | final PsiElement firstElement; 53 | final PsiElement lastElement; 54 | final PsiElement parent; 55 | if (matchOptions.getScope() == null) { 56 | final PsiElement[] elements = MatcherImplUtil.createTreeFromText( 57 | in, 58 | new PatternContextInfo(sourceIsFile ? PatternTreeContext.File : PatternTreeContext.Block), 59 | sourceFileType, 60 | sourceDialect, 61 | project, 62 | createPhysicalFile 63 | ); 64 | 65 | firstElement = elements[0]; 66 | lastElement = elements[elements.length - 1]; 67 | parent = firstElement.getParent(); 68 | 69 | matchOptions.setScope(new LocalSearchScope(elements)); 70 | } else { 71 | parent = ((LocalSearchScope) matchOptions.getScope()).getScope()[0]; 72 | firstElement = parent.getFirstChild(); 73 | lastElement = parent.getLastChild(); 74 | } 75 | 76 | final CollectingMatchResultSink sink = new CollectingMatchResultSink(); 77 | matcher.testFindMatches(sink); 78 | 79 | final Listfrom: |
|
to: |
|
{0}
to:
--------------------------------------------------------------------------------
/plugin/src/main/resources/META-INF/plugin.xml:
--------------------------------------------------------------------------------
1 | 4 | Data-driven type migration. 5 |
6 | 7 |8 | Data-driven type migration. 9 |
10 | 11 | -------------------------------------------------------------------------------- /plugin/src/test/java/org/jetbrains/research/ddtm/ide/TypeChangeIntentionTest.java: -------------------------------------------------------------------------------- 1 | package org.jetbrains.research.ddtm.ide; 2 | 3 | import com.intellij.openapi.command.WriteCommandAction; 4 | import com.intellij.openapi.projectRoots.JavaSdk; 5 | import com.intellij.openapi.projectRoots.Sdk; 6 | import com.intellij.openapi.vfs.VirtualFile; 7 | import com.intellij.pom.java.LanguageLevel; 8 | import com.intellij.psi.PsiElement; 9 | import com.intellij.psi.PsiFile; 10 | import com.intellij.psi.PsiManager; 11 | import com.intellij.testFramework.LightProjectDescriptor; 12 | import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase; 13 | import org.jetbrains.annotations.NotNull; 14 | import org.jetbrains.research.ddtm.data.TypeChangeRulesStorage; 15 | import org.jetbrains.research.ddtm.data.enums.InvocationWorkflow; 16 | import org.jetbrains.research.ddtm.ide.migration.TypeChangeProcessor; 17 | import org.jetbrains.research.ddtm.utils.TypeReference; 18 | 19 | import java.io.File; 20 | import java.nio.file.Path; 21 | import java.util.List; 22 | import java.util.Set; 23 | 24 | public class TypeChangeIntentionTest extends LightJavaCodeInsightFixtureTestCase { 25 | private static final String JDK_HOME_DIRECTORY = System.getProperty("jdk.home.path"); 26 | private static final String MOCK_JDK_1_8_NAME = "mockJDK-1.8"; 27 | private static final String INITIAL_FILE_NAME = "Initial.java"; 28 | private static final String EXPECTED_FILE_NAME = "Expected.java"; 29 | 30 | @Override 31 | protected String getTestDataPath() { 32 | return Path.of("src", "test", "resources", "testData").toString(); 33 | } 34 | 35 | private String getMockJdkPath() { 36 | return Path.of("src", "test", "resources", MOCK_JDK_1_8_NAME).toString(); 37 | } 38 | 39 | @Override 40 | protected @NotNull LightProjectDescriptor getProjectDescriptor() { 41 | return new ProjectDescriptor(LanguageLevel.JDK_1_8) { 42 | @Override 43 | public Sdk getSdk() { 44 | return JavaSdk.getInstance().createJdk(Path.of(JDK_HOME_DIRECTORY).getFileName().toString(), JDK_HOME_DIRECTORY, false); 45 | } 46 | }; 47 | } 48 | 49 | protected void doTest(String testName, TypeReference> sourceType, TypeReference> targetType) { 50 | final VirtualFile directory = myFixture.copyDirectoryToProject(testName, testName); 51 | final VirtualFile initialFile = directory.findChild(INITIAL_FILE_NAME); 52 | final VirtualFile expectedFile = directory.findChild(EXPECTED_FILE_NAME); 53 | assertNotNull(initialFile); 54 | assertNotNull(expectedFile); 55 | 56 | myFixture.configureFromExistingVirtualFile(initialFile); 57 | final int offset = myFixture.getCaretOffset(); 58 | PsiElement element = myFixture.getFile().findElementAt(offset); 59 | final var storage = getProject().getService(TypeChangeRulesStorage.class); 60 | 61 | final var result = storage.findPattern(sourceType.getType().getTypeName(), targetType.getType().getTypeName()); 62 | assertTrue("No such pattern with specified types", result.isPresent()); 63 | final var pattern = result.get(); 64 | 65 | final var processor = (new TypeChangeProcessor(getProject(), InvocationWorkflow.PROACTIVE)); 66 | WriteCommandAction.runWriteCommandAction(getProject(), () -> processor.run(element, pattern)); 67 | 68 | PsiFile psiFile = PsiManager.getInstance(getProject()).findFile(expectedFile); 69 | assertNotNull(psiFile); 70 | 71 | String expectedSrc = psiFile.getText().strip(); 72 | String actualSrc = getFile().getText().strip(); 73 | assertEquals(expectedSrc, actualSrc); 74 | } 75 | 76 | public void testFileToPath() { 77 | doTest("TestFileToPath", 78 | new TypeReference