Quick Fixes: Implement quickfix for missing library

This commit is contained in:
Alexey Sedunov
2015-10-02 19:57:50 +03:00
parent f59e56b7e9
commit 1a36c3e29a
10 changed files with 188 additions and 30 deletions
+1
View File
@@ -6,6 +6,7 @@
<CLASSES>
<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/jcommander.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
@@ -25,8 +25,10 @@ import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.roots.ui.configuration.libraryEditor.NewLibraryEditor;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.vfs.VfsUtil;
import kotlin.jvm.functions.Function0;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.idea.js.KotlinJavaScriptLibraryManager;
import org.jetbrains.kotlin.idea.util.application.ApplicationUtilsKt;
import org.jetbrains.kotlin.utils.PathUtil;
import java.io.File;
@@ -121,42 +123,49 @@ public class ConfigLibraryUtil {
}
public static void removeLibrary(@NotNull final Module module, @NotNull final String libraryName) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
ModuleRootManager rootManager = ModuleRootManager.getInstance(module);
ModifiableRootModel model = rootManager.getModifiableModel();
public static boolean removeLibrary(@NotNull final Module module, @NotNull final String libraryName) {
return ApplicationUtilsKt.runWriteAction(
new Function0<Boolean>() {
@Override
public Boolean invoke() {
boolean removed = false;
for (OrderEntry orderEntry : model.getOrderEntries()) {
if (orderEntry instanceof LibraryOrderEntry) {
LibraryOrderEntry libraryOrderEntry = (LibraryOrderEntry) orderEntry;
ModuleRootManager rootManager = ModuleRootManager.getInstance(module);
ModifiableRootModel model = rootManager.getModifiableModel();
Library library = libraryOrderEntry.getLibrary();
if (library != null) {
String name = library.getName();
if (name != null && name.equals(libraryName)) {
for (OrderEntry orderEntry : model.getOrderEntries()) {
if (orderEntry instanceof LibraryOrderEntry) {
LibraryOrderEntry libraryOrderEntry = (LibraryOrderEntry) orderEntry;
// Dispose attached roots
Library.ModifiableModel modifiableModel = library.getModifiableModel();
for (String rootUrl : library.getRootProvider().getUrls(OrderRootType.CLASSES)) {
modifiableModel.removeRoot(rootUrl, OrderRootType.CLASSES);
Library library = libraryOrderEntry.getLibrary();
if (library != null) {
String name = library.getName();
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)
DEPRECATED_TYPE_PARAMETER_SYNTAX.registerFactory(MigrateTypeParameterListFix)
UNRESOLVED_REFERENCE.registerFactory(KotlinAddOrderEntryActionFactory)
}
}
+14
View File
@@ -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
View File
@@ -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
View File
@@ -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()
}
}
+14
View File
@@ -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.lang.annotation.ProblemGroup;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.projectRoots.JavaSdk;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.startup.StartupManager;
@@ -95,8 +96,10 @@ public abstract class AbstractQuickFixTest extends KotlinLightQuickFixTestCase {
@SuppressWarnings({"AssignmentToStaticFieldFromInstanceMethod", "CallToPrintStackTrace"})
@Override
public void run() {
String fileText = "";
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.bringRealEditorBack();
@@ -110,11 +113,21 @@ public abstract class AbstractQuickFixTest extends KotlinLightQuickFixTestCase {
catch (Throwable e) {
e.printStackTrace();
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 {
Pair<String, Boolean> pair = quickFixTestCase.parseActionHintImpl(quickFixTestCase.getFile(), contents);
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")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)