Quick Fixes: Implement quickfix for missing library
This commit is contained in:
Generated
+1
@@ -6,6 +6,7 @@
|
|||||||
<CLASSES>
|
<CLASSES>
|
||||||
<root url="jar://$PROJECT_DIR$/ideaSDK/plugins/testng/lib/testng-plugin.jar!/" />
|
<root url="jar://$PROJECT_DIR$/ideaSDK/plugins/testng/lib/testng-plugin.jar!/" />
|
||||||
<root url="jar://$PROJECT_DIR$/ideaSDK/plugins/testng/lib/testng.jar!/" />
|
<root url="jar://$PROJECT_DIR$/ideaSDK/plugins/testng/lib/testng.jar!/" />
|
||||||
|
<root url="jar://$PROJECT_DIR$/ideaSDK/plugins/testng/lib/jcommander.jar!/" />
|
||||||
</CLASSES>
|
</CLASSES>
|
||||||
<JAVADOC />
|
<JAVADOC />
|
||||||
<SOURCES>
|
<SOURCES>
|
||||||
|
|||||||
+38
-29
@@ -25,8 +25,10 @@ import com.intellij.openapi.roots.libraries.Library;
|
|||||||
import com.intellij.openapi.roots.ui.configuration.libraryEditor.NewLibraryEditor;
|
import com.intellij.openapi.roots.ui.configuration.libraryEditor.NewLibraryEditor;
|
||||||
import com.intellij.openapi.util.Computable;
|
import com.intellij.openapi.util.Computable;
|
||||||
import com.intellij.openapi.vfs.VfsUtil;
|
import com.intellij.openapi.vfs.VfsUtil;
|
||||||
|
import kotlin.jvm.functions.Function0;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.kotlin.idea.js.KotlinJavaScriptLibraryManager;
|
import org.jetbrains.kotlin.idea.js.KotlinJavaScriptLibraryManager;
|
||||||
|
import org.jetbrains.kotlin.idea.util.application.ApplicationUtilsKt;
|
||||||
import org.jetbrains.kotlin.utils.PathUtil;
|
import org.jetbrains.kotlin.utils.PathUtil;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -121,42 +123,49 @@ public class ConfigLibraryUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void removeLibrary(@NotNull final Module module, @NotNull final String libraryName) {
|
public static boolean removeLibrary(@NotNull final Module module, @NotNull final String libraryName) {
|
||||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
return ApplicationUtilsKt.runWriteAction(
|
||||||
@Override
|
new Function0<Boolean>() {
|
||||||
public void run() {
|
@Override
|
||||||
ModuleRootManager rootManager = ModuleRootManager.getInstance(module);
|
public Boolean invoke() {
|
||||||
ModifiableRootModel model = rootManager.getModifiableModel();
|
boolean removed = false;
|
||||||
|
|
||||||
for (OrderEntry orderEntry : model.getOrderEntries()) {
|
ModuleRootManager rootManager = ModuleRootManager.getInstance(module);
|
||||||
if (orderEntry instanceof LibraryOrderEntry) {
|
ModifiableRootModel model = rootManager.getModifiableModel();
|
||||||
LibraryOrderEntry libraryOrderEntry = (LibraryOrderEntry) orderEntry;
|
|
||||||
|
|
||||||
Library library = libraryOrderEntry.getLibrary();
|
for (OrderEntry orderEntry : model.getOrderEntries()) {
|
||||||
if (library != null) {
|
if (orderEntry instanceof LibraryOrderEntry) {
|
||||||
String name = library.getName();
|
LibraryOrderEntry libraryOrderEntry = (LibraryOrderEntry) orderEntry;
|
||||||
if (name != null && name.equals(libraryName)) {
|
|
||||||
|
|
||||||
// Dispose attached roots
|
Library library = libraryOrderEntry.getLibrary();
|
||||||
Library.ModifiableModel modifiableModel = library.getModifiableModel();
|
if (library != null) {
|
||||||
for (String rootUrl : library.getRootProvider().getUrls(OrderRootType.CLASSES)) {
|
String name = library.getName();
|
||||||
modifiableModel.removeRoot(rootUrl, OrderRootType.CLASSES);
|
if (name != null && name.equals(libraryName)) {
|
||||||
|
|
||||||
|
// Dispose attached roots
|
||||||
|
Library.ModifiableModel modifiableModel = library.getModifiableModel();
|
||||||
|
for (String rootUrl : library.getRootProvider().getUrls(OrderRootType.CLASSES)) {
|
||||||
|
modifiableModel.removeRoot(rootUrl, OrderRootType.CLASSES);
|
||||||
|
}
|
||||||
|
for (String rootUrl : library.getRootProvider().getUrls(OrderRootType.SOURCES)) {
|
||||||
|
modifiableModel.removeRoot(rootUrl, OrderRootType.SOURCES);
|
||||||
|
}
|
||||||
|
modifiableModel.commit();
|
||||||
|
|
||||||
|
model.getModuleLibraryTable().removeLibrary(library);
|
||||||
|
|
||||||
|
removed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (String rootUrl : library.getRootProvider().getUrls(OrderRootType.SOURCES)) {
|
|
||||||
modifiableModel.removeRoot(rootUrl, OrderRootType.SOURCES);
|
|
||||||
}
|
|
||||||
modifiableModel.commit();
|
|
||||||
|
|
||||||
model.getModuleLibraryTable().removeLibrary(library);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model.commit();
|
||||||
|
|
||||||
|
return removed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
);
|
||||||
model.commit();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2015 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.quickfix
|
||||||
|
|
||||||
|
import com.intellij.codeInsight.daemon.impl.quickfix.OrderEntryFix
|
||||||
|
import com.intellij.codeInsight.daemon.impl.quickfix.QuickFixActionRegistrarImpl
|
||||||
|
import com.intellij.codeInsight.intention.IntentionAction
|
||||||
|
import com.intellij.openapi.util.TextRange
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.PsiReference
|
||||||
|
import com.intellij.psi.PsiReferenceBase
|
||||||
|
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||||
|
import org.jetbrains.kotlin.idea.references.JetSimpleNameReference.ShorteningMode
|
||||||
|
import org.jetbrains.kotlin.idea.references.mainReference
|
||||||
|
import org.jetbrains.kotlin.psi.JetElement
|
||||||
|
import org.jetbrains.kotlin.psi.JetSimpleNameExpression
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElement
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||||
|
|
||||||
|
public object KotlinAddOrderEntryActionFactory : JetIntentionActionsFactory() {
|
||||||
|
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction>? {
|
||||||
|
val simpleExpression = diagnostic.psiElement as? JetSimpleNameExpression ?: return emptyList()
|
||||||
|
val refElement = simpleExpression.getQualifiedElement()
|
||||||
|
|
||||||
|
val reference = object: PsiReferenceBase<JetElement>(refElement) {
|
||||||
|
override fun resolve() = null
|
||||||
|
|
||||||
|
override fun getVariants() = PsiReference.EMPTY_ARRAY
|
||||||
|
|
||||||
|
override fun getRangeInElement(): TextRange? {
|
||||||
|
val offset = simpleExpression.startOffset - refElement.startOffset
|
||||||
|
return TextRange(offset, offset + simpleExpression.textLength)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getCanonicalText() = refElement.text
|
||||||
|
|
||||||
|
override fun bindToElement(element: PsiElement): PsiElement {
|
||||||
|
return simpleExpression.mainReference.bindToElement(element, ShorteningMode.FORCED_SHORTENING)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
return OrderEntryFix.registerFixes(QuickFixActionRegistrarImpl(null), reference) as List<IntentionAction>? ?: emptyList()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -338,5 +338,7 @@ public class QuickFixRegistrar : QuickFixContributor {
|
|||||||
CALLABLE_REFERENCE_TO_MEMBER_OR_EXTENSION_WITH_EMPTY_LHS.registerFactory(AddTypeToLHSOfCallableReferenceFix)
|
CALLABLE_REFERENCE_TO_MEMBER_OR_EXTENSION_WITH_EMPTY_LHS.registerFactory(AddTypeToLHSOfCallableReferenceFix)
|
||||||
|
|
||||||
DEPRECATED_TYPE_PARAMETER_SYNTAX.registerFactory(MigrateTypeParameterListFix)
|
DEPRECATED_TYPE_PARAMETER_SYNTAX.registerFactory(MigrateTypeParameterListFix)
|
||||||
|
|
||||||
|
UNRESOLVED_REFERENCE.registerFactory(KotlinAddOrderEntryActionFactory)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
// "Add 'JUnit4' to classpath" "true"
|
||||||
|
// ERROR: Unresolved reference: Before
|
||||||
|
// ERROR: Unresolved reference: junit
|
||||||
|
// UNCONFIGURE_LIBRARY: JUnit4
|
||||||
|
package some
|
||||||
|
|
||||||
|
import org.<caret>junit.Before
|
||||||
|
|
||||||
|
open class KBase {
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
}
|
||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
// "Add 'JUnit4' to classpath" "true"
|
||||||
|
// ERROR: Unresolved reference: Before
|
||||||
|
// ERROR: Unresolved reference: junit
|
||||||
|
// UNCONFIGURE_LIBRARY: JUnit4
|
||||||
|
package some
|
||||||
|
|
||||||
|
import org.junit.Before
|
||||||
|
|
||||||
|
open class KBase {
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
}
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
// "Add 'testng' to classpath" "true"
|
||||||
|
// ERROR: Unresolved reference: BeforeMethod
|
||||||
|
// ERROR: Unresolved reference: testng
|
||||||
|
// UNCONFIGURE_LIBRARY: testng
|
||||||
|
package some
|
||||||
|
|
||||||
|
abstract class KBase {
|
||||||
|
@<caret>BeforeMethod
|
||||||
|
fun setUp() {
|
||||||
|
throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
// "Add 'testng' to classpath" "true"
|
||||||
|
// ERROR: Unresolved reference: BeforeMethod
|
||||||
|
// ERROR: Unresolved reference: testng
|
||||||
|
// UNCONFIGURE_LIBRARY: testng
|
||||||
|
package some
|
||||||
|
|
||||||
|
import org.testng.annotations.BeforeMethod
|
||||||
|
|
||||||
|
abstract class KBase {
|
||||||
|
@BeforeMethod
|
||||||
|
fun setUp() {
|
||||||
|
throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,6 +24,7 @@ import com.intellij.codeInspection.SuppressableProblemGroup;
|
|||||||
import com.intellij.ide.startup.impl.StartupManagerImpl;
|
import com.intellij.ide.startup.impl.StartupManagerImpl;
|
||||||
import com.intellij.lang.annotation.ProblemGroup;
|
import com.intellij.lang.annotation.ProblemGroup;
|
||||||
import com.intellij.openapi.command.CommandProcessor;
|
import com.intellij.openapi.command.CommandProcessor;
|
||||||
|
import com.intellij.openapi.module.Module;
|
||||||
import com.intellij.openapi.projectRoots.JavaSdk;
|
import com.intellij.openapi.projectRoots.JavaSdk;
|
||||||
import com.intellij.openapi.projectRoots.Sdk;
|
import com.intellij.openapi.projectRoots.Sdk;
|
||||||
import com.intellij.openapi.startup.StartupManager;
|
import com.intellij.openapi.startup.StartupManager;
|
||||||
@@ -95,8 +96,10 @@ public abstract class AbstractQuickFixTest extends KotlinLightQuickFixTestCase {
|
|||||||
@SuppressWarnings({"AssignmentToStaticFieldFromInstanceMethod", "CallToPrintStackTrace"})
|
@SuppressWarnings({"AssignmentToStaticFieldFromInstanceMethod", "CallToPrintStackTrace"})
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
String fileText = "";
|
||||||
try {
|
try {
|
||||||
String contents = StringUtil.convertLineSeparators(FileUtil.loadFile(testFile, CharsetToolkit.UTF8_CHARSET));
|
fileText = FileUtil.loadFile(testFile, CharsetToolkit.UTF8_CHARSET);
|
||||||
|
String contents = StringUtil.convertLineSeparators(fileText);
|
||||||
quickFixTestCase.configureFromFileText(testFile.getName(), contents);
|
quickFixTestCase.configureFromFileText(testFile.getName(), contents);
|
||||||
quickFixTestCase.bringRealEditorBack();
|
quickFixTestCase.bringRealEditorBack();
|
||||||
|
|
||||||
@@ -110,11 +113,21 @@ public abstract class AbstractQuickFixTest extends KotlinLightQuickFixTestCase {
|
|||||||
catch (Throwable e) {
|
catch (Throwable e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
fail(testName);
|
fail(testName);
|
||||||
|
} finally {
|
||||||
|
unconfigureLibrariesAsSpecified(fileText);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, "", "");
|
}, "", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void unconfigureLibrariesAsSpecified(String fileText) {
|
||||||
|
Module module = getModule();
|
||||||
|
for (String libraryName : InTextDirectivesUtils.findListWithPrefixes(fileText, "// UNCONFIGURE_LIBRARY: ")) {
|
||||||
|
if (ConfigLibraryUtil.removeLibrary(module, libraryName)) continue;
|
||||||
|
fail("Library '" + libraryName + "' wasn't found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void applyAction(String contents, QuickFixTestCase quickFixTestCase, String testName, String testFullPath) throws Exception {
|
private static void applyAction(String contents, QuickFixTestCase quickFixTestCase, String testName, String testFullPath) throws Exception {
|
||||||
Pair<String, Boolean> pair = quickFixTestCase.parseActionHintImpl(quickFixTestCase.getFile(), contents);
|
Pair<String, Boolean> pair = quickFixTestCase.parseActionHintImpl(quickFixTestCase.getFile(), contents);
|
||||||
String text = pair.getFirst();
|
String text = pair.getFirst();
|
||||||
|
|||||||
@@ -4077,6 +4077,27 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("idea/testData/quickfix/libraries")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class Libraries extends AbstractQuickFixTest {
|
||||||
|
public void testAllFilesPresentInLibraries() throws Exception {
|
||||||
|
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/libraries"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("junit.kt")
|
||||||
|
public void testJunit() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/libraries/junit.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("testNG.kt")
|
||||||
|
public void testTestNG() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/libraries/testNG.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("idea/testData/quickfix/migration")
|
@TestMetadata("idea/testData/quickfix/migration")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
Reference in New Issue
Block a user