mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-78831 Remove unnecessary semicolons intention
This commit is contained in:
@@ -59,7 +59,7 @@ public class CommonRefactoringUtil {
|
||||
}
|
||||
}
|
||||
|
||||
public static void showErrorHint(Project project, @Nullable Editor editor, String message, String title, String helpId) {
|
||||
public static void showErrorHint(Project project, @Nullable Editor editor, String message, String title, @Nullable @NonNls String helpId) {
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) throw new RefactoringErrorHintException(message);
|
||||
|
||||
if (editor == null) {
|
||||
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
print 2
|
||||
print 3
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
print 2<spot>;</spot>
|
||||
print 3
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
<span style="font-family: verdana,serif; font-size: small;">Removes unnecessary semicolons from selected text or a semicolon under caret if it is unnecessary.</span>
|
||||
</body>
|
||||
</html>
|
||||
@@ -914,6 +914,11 @@
|
||||
<categoryKey>intention.category.groovy/intention.category.groovy.style</categoryKey>
|
||||
<className>org.jetbrains.plugins.groovy.intentions.style.JavaStylePropertiesInvocationIntention</className>
|
||||
</intentionAction>
|
||||
<intentionAction>
|
||||
<bundleName>org.jetbrains.plugins.groovy.intentions.GroovyIntentionsBundle</bundleName>
|
||||
<categoryKey>intention.category.groovy/intention.category.groovy.style</categoryKey>
|
||||
<className>org.jetbrains.plugins.groovy.intentions.style.RemoveUnnecessarySemicolonsIntention</className>
|
||||
</intentionAction>
|
||||
<intentionAction>
|
||||
<bundleName>org.jetbrains.plugins.groovy.intentions.GroovyIntentionsBundle</bundleName>
|
||||
<categoryKey>intention.category.groovy/intention.category.groovy.style</categoryKey>
|
||||
|
||||
+3
@@ -138,3 +138,6 @@ convert.to.geese.braces.intention.family.name=Format closing closure braces in o
|
||||
|
||||
convert.from.geese.braces.intention.name=Format braces in separate lines
|
||||
convert.from.geese.braces.intention.family.name=Format braces in separate lines
|
||||
remove.unnecessary.semicolons.name=Remove unnecessary semicolons
|
||||
remove.unnecessary.semicolons.family.name=Remove unnecessary semicolons from selected text
|
||||
no.unnecessary.semicolons.found=No unnecessary semicolons found
|
||||
|
||||
+198
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Copyright 2000-2011 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.plugins.groovy.intentions.style;
|
||||
|
||||
import com.intellij.codeInsight.intention.IntentionAction;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.SelectionModel;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiRecursiveElementVisitor;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.refactoring.util.CommonRefactoringUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.groovy.intentions.GroovyIntentionsBundle;
|
||||
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* @author Max Medvedev
|
||||
*/
|
||||
public class RemoveUnnecessarySemicolonsIntention implements IntentionAction {
|
||||
@NotNull
|
||||
@Override
|
||||
public String getText() {
|
||||
return GroovyIntentionsBundle.message("remove.unnecessary.semicolons.name");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return GroovyIntentionsBundle.message("remove.unnecessary.semicolons.family.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
|
||||
if (!(file instanceof GroovyFileBase) || editor.getSelectionModel().hasBlockSelection()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (editor.getSelectionModel().hasSelection()) return true;
|
||||
|
||||
int offset = editor.getCaretModel().getOffset();
|
||||
if (offset >= editor.getDocument().getTextLength()) offset = editor.getDocument().getTextLength() - 1;
|
||||
final PsiElement element = file.findElementAt(offset);
|
||||
if (element == null) return false;
|
||||
if (element.getNode().getElementType() == GroovyTokenTypes.mSEMI) return true;
|
||||
|
||||
final PsiElement next = PsiTreeUtil.nextLeaf(element);
|
||||
if (next != null && next.getNode().getElementType() == GroovyTokenTypes.mSEMI) return true;
|
||||
|
||||
|
||||
final PsiElement prev = PsiTreeUtil.prevLeaf(element);
|
||||
if (prev != null && prev.getNode().getElementType() == GroovyTokenTypes.mSEMI) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
|
||||
final SelectionModel selectionModel = editor.getSelectionModel();
|
||||
if (selectionModel.hasBlockSelection()) return;
|
||||
|
||||
Document document = editor.getDocument();
|
||||
if (selectionModel.hasSelection()) {
|
||||
final int start = selectionModel.getSelectionStart();
|
||||
final int end = selectionModel.getSelectionEnd();
|
||||
final TextRange range = new TextRange(start, end);
|
||||
|
||||
final ArrayList<PsiElement> colons = new ArrayList<PsiElement>();
|
||||
file.accept(new PsiRecursiveElementVisitor() {
|
||||
@Override
|
||||
public void visitElement(PsiElement element) {
|
||||
if (!range.intersects(element.getTextRange())) return;
|
||||
|
||||
final IElementType elementType = element.getNode().getElementType();
|
||||
if (elementType == GroovyTokenTypes.mSEMI) {
|
||||
colons.add(element);
|
||||
}
|
||||
else {
|
||||
super.visitElement(element);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
boolean removed = false;
|
||||
for (PsiElement colon : colons) {
|
||||
final boolean b = checkAndRemove(project, colon, document);
|
||||
removed = removed || b;
|
||||
}
|
||||
|
||||
if (!removed) {
|
||||
CommonRefactoringUtil.showErrorHint(project, editor, GroovyIntentionsBundle.message("no.unnecessary.semicolons.found"),
|
||||
GroovyIntentionsBundle.message("remove.unnecessary.semicolons.name"), null);
|
||||
}
|
||||
}
|
||||
else {
|
||||
int offset = editor.getCaretModel().getOffset();
|
||||
if (offset >= document.getTextLength()) offset = document.getTextLength() - 1;
|
||||
final PsiElement element = file.findElementAt(offset);
|
||||
if (element == null) return;
|
||||
if (checkAndRemove(project, element, document)) return;
|
||||
|
||||
if (checkAndRemove(project, PsiTreeUtil.nextLeaf(element), document)) return;
|
||||
if (checkAndRemove(project, PsiTreeUtil.prevLeaf(element), document)) return;
|
||||
|
||||
CommonRefactoringUtil.showErrorHint(project, editor, GroovyIntentionsBundle.message("no.unnecessary.semicolons.found"),
|
||||
GroovyIntentionsBundle.message("remove.unnecessary.semicolons.name"), null);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean checkAndRemove(Project project, @Nullable PsiElement element, Document document) {
|
||||
if (element != null && element.getNode().getElementType() == GroovyTokenTypes.mSEMI) {
|
||||
if (isColonUnnecessary(element, document.getText(), project)) {
|
||||
element.delete();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isColonUnnecessary(PsiElement colon, String text, Project project) {
|
||||
final GrStatement prev = getPreviousStatement(colon);
|
||||
final GrStatement next = getNextStatement(colon);
|
||||
|
||||
if (prev == null || next == null) return true;
|
||||
|
||||
final int startOffset = prev.getTextRange().getStartOffset();
|
||||
final int endOffset = next.getTextRange().getEndOffset();
|
||||
|
||||
final int offset = colon.getTextRange().getStartOffset();
|
||||
final String statementWithoutColon = text.substring(startOffset, offset) + text.substring(offset + 1, endOffset);
|
||||
final GroovyFile file = GroovyPsiElementFactory.getInstance(project).createGroovyFile(statementWithoutColon, false, null);
|
||||
final GrStatement[] statements = file.getStatements();
|
||||
if (statements.length != 2) return false;
|
||||
|
||||
return checkEquality(prev, statements[0]) && checkEquality(next, statements[1]);
|
||||
}
|
||||
|
||||
private static boolean checkEquality(PsiElement l, PsiElement r) {
|
||||
if (!l.getText().equals(r.getText())) return false;
|
||||
if (l.getNode().getElementType() != r.getNode().getElementType()) return false;
|
||||
|
||||
final PsiElement[] lChildren = l.getChildren();
|
||||
final PsiElement[] rChildren = r.getChildren();
|
||||
|
||||
if (lChildren.length != rChildren.length) return false;
|
||||
|
||||
for (int i = 0; i < rChildren.length; i++) {
|
||||
if (!checkEquality(lChildren[i], rChildren[i])) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static GrStatement getPreviousStatement(PsiElement colon) {
|
||||
final PsiElement prev = PsiUtil.skipWhitespaces(colon.getPrevSibling(), false);
|
||||
if (prev instanceof GrStatement) return (GrStatement)prev;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static GrStatement getNextStatement(PsiElement colon) {
|
||||
final PsiElement next = PsiUtil.skipWhitespaces(colon.getNextSibling(), true);
|
||||
if (next instanceof GrStatement) return (GrStatement)next;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean startInWriteAction() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -188,7 +188,7 @@ public abstract class GroovyPsiElementFactory implements JVMElementFactory {
|
||||
|
||||
public abstract GrAnnotation createAnnotationFromText(String annoText);
|
||||
|
||||
public abstract GroovyFile createGroovyFile(String text, boolean isPhysical, PsiElement context);
|
||||
public abstract GroovyFile createGroovyFile(String text, boolean isPhysical, @Nullable PsiElement context);
|
||||
|
||||
public abstract GrMethod createMethodFromText(String modifier, String name, String type, String[] paramTypes, PsiElement context);
|
||||
|
||||
|
||||
+549
@@ -0,0 +1,549 @@
|
||||
/*
|
||||
* Copyright 2000-2011 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.plugins.groovy.intentions
|
||||
|
||||
import com.intellij.refactoring.util.CommonRefactoringUtil.RefactoringErrorHintException
|
||||
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
|
||||
import org.jetbrains.plugins.groovy.util.TestUtils
|
||||
|
||||
/**
|
||||
* @author Max Medvedev
|
||||
*/
|
||||
class RemoveUnnecessarySemicolonTest extends LightCodeInsightFixtureTestCase {
|
||||
private static final String hint = GroovyIntentionsBundle.message('remove.unnecessary.semicolons.name');
|
||||
|
||||
@Override
|
||||
protected String getBasePath() {
|
||||
return "${TestUtils.testDataPath}intentions/removeUnnecessaryBraces/";
|
||||
}
|
||||
|
||||
void testSimpleCase1() {
|
||||
doTest('print 2;<caret>\nprint 3', 'print 2\nprint 3')
|
||||
}
|
||||
|
||||
void testSimpleCase2() {
|
||||
doTest('print 2<caret>;\nprint 3', 'print 2\nprint 3')
|
||||
}
|
||||
|
||||
void testSimpleCase3() {
|
||||
doTest('prin<selection>t 2;\np</selection>rint 3', 'prin<selection>t 2\np</selection>rint 3')
|
||||
}
|
||||
|
||||
void testDontRemoveSimple() {
|
||||
doTest('print 2<caret>; print 3')
|
||||
}
|
||||
|
||||
void testClosure() {
|
||||
doTest('print( a )<caret>;\n{->print 3}')
|
||||
}
|
||||
|
||||
private doTest(String before, String after) {
|
||||
myFixture.configureByText('a.groovy', before)
|
||||
def intentions = myFixture.filterAvailableIntentions(hint)
|
||||
assertEquals(1, intentions.size())
|
||||
|
||||
myFixture.launchAction(intentions[0])
|
||||
myFixture.checkResult(after)
|
||||
}
|
||||
|
||||
private doTest(String text) {
|
||||
try {
|
||||
doTest(text, text)
|
||||
}
|
||||
catch (RefactoringErrorHintException e) {
|
||||
return;
|
||||
}
|
||||
fail('RefactoringErrorHintException should be thrown')
|
||||
}
|
||||
|
||||
private doFalseTest(String before) {
|
||||
myFixture.configureByText('a.groovy', before)
|
||||
def intentions = myFixture.filterAvailableIntentions(hint)
|
||||
assertEmpty(intentions)
|
||||
}
|
||||
|
||||
void testBig() {
|
||||
doTest('''\
|
||||
<selection>/*
|
||||
* Copyright 2000-2011 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 com.intellij.refactoring.util;
|
||||
|
||||
import com.intellij.codeInsight.hint.HintManager;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.fileTypes.FileTypeManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.JarFileSystem;
|
||||
import com.intellij.openapi.vfs.ReadonlyStatusHandler;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.refactoring.RefactoringBundle;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import gnu.trove.THashSet;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* @author ven
|
||||
*/
|
||||
public class CommonRefactoringUtil {
|
||||
private CommonRefactoringUtil() {}
|
||||
|
||||
public static void showErrorMessage(String title, String message, @Nullable @NonNls String helpId, @NotNull Project project) {
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) throw new RuntimeException(message);
|
||||
RefactoringMessageDialog dialog = new RefactoringMessageDialog(title, message, helpId, "OptionPane.errorIcon", false, project);
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fatal refactoring problem during unit test run. Corresponds to message of modal dialog shown during user driven refactoring.
|
||||
*/
|
||||
public static class RefactoringErrorHintException extends RuntimeException {
|
||||
public RefactoringErrorHintException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static void showErrorHint(Project project, @Nullable Editor editor, String message, String title, @Nullable @NonNls String helpId) {
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) throw new RefactoringErrorHintException(message);
|
||||
|
||||
if (editor == null) {
|
||||
showErrorMessage(title, message, helpId, project);
|
||||
}
|
||||
else {
|
||||
HintManager.getInstance().showErrorHint(editor, message);
|
||||
}
|
||||
}
|
||||
|
||||
@NonNls
|
||||
public static String htmlEmphasize(String text) {
|
||||
return "<b><code>" + text + "</code></b>";
|
||||
}
|
||||
|
||||
public static boolean checkReadOnlyStatus(@NotNull PsiElement element) {
|
||||
final VirtualFile file = element.getContainingFile().getVirtualFile();
|
||||
return file != null && !ReadonlyStatusHandler.getInstance(element.getProject()).ensureFilesWritable(file).hasReadonlyFiles();
|
||||
}
|
||||
|
||||
public static boolean checkReadOnlyStatus(@NotNull Project project, @NotNull PsiElement element) {
|
||||
return checkReadOnlyStatus(element, project, RefactoringBundle.message("refactoring.cannot.be.performed"));
|
||||
}
|
||||
|
||||
public static boolean checkReadOnlyStatus(@NotNull Project project, @NotNull PsiElement... elements) {
|
||||
return checkReadOnlyStatus(Arrays.asList(elements), project, RefactoringBundle.message("refactoring.cannot.be.performed"), false, true);
|
||||
}
|
||||
|
||||
public static boolean checkReadOnlyStatus(@NotNull PsiElement element, @NotNull Project project, String messagePrefix) {
|
||||
return element.isWritable() ||
|
||||
checkReadOnlyStatus(Collections.singleton(element), project, messagePrefix, false, true);
|
||||
}
|
||||
|
||||
public static boolean checkReadOnlyStatusRecursively(@NotNull Project project, @NotNull Collection<? extends PsiElement> elements) {
|
||||
return checkReadOnlyStatus(elements, project, RefactoringBundle.message("refactoring.cannot.be.performed"), true, false);
|
||||
}
|
||||
public static boolean checkReadOnlyStatusRecursively(@NotNull Project project, @NotNull Collection<? extends PsiElement> elements, boolean notifyOnFail) {
|
||||
return checkReadOnlyStatus(elements, project, RefactoringBundle.message("refactoring.cannot.be.performed"), true, notifyOnFail);
|
||||
}
|
||||
|
||||
private static boolean checkReadOnlyStatus(@NotNull Collection<? extends PsiElement> elements,
|
||||
@NotNull Project project,
|
||||
final String messagePrefix,
|
||||
boolean recursively,
|
||||
final boolean notifyOnFail) {
|
||||
final Collection<VirtualFile> readonly = new THashSet<VirtualFile>(); // not writable, but could be checked out
|
||||
final Collection<VirtualFile> failed = new THashSet<VirtualFile>(); // those located in jars
|
||||
boolean seenNonWritablePsiFilesWithoutVirtualFile = false;
|
||||
|
||||
for (PsiElement element : elements) {
|
||||
if (element instanceof PsiDirectory) {
|
||||
final PsiDirectory dir = (PsiDirectory)element;
|
||||
final VirtualFile vFile = dir.getVirtualFile();
|
||||
if (vFile.getFileSystem() instanceof JarFileSystem) {
|
||||
failed.add(vFile);
|
||||
}
|
||||
else {
|
||||
if (recursively) {
|
||||
addVirtualFiles(vFile, readonly);
|
||||
}
|
||||
else {
|
||||
readonly.add(vFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (element instanceof PsiDirectoryContainer) {
|
||||
final PsiDirectory[] directories = ((PsiDirectoryContainer)element).getDirectories();
|
||||
for (PsiDirectory directory : directories) {
|
||||
VirtualFile virtualFile = directory.getVirtualFile();
|
||||
if (recursively) {
|
||||
if (virtualFile.getFileSystem() instanceof JarFileSystem) {
|
||||
failed.add(virtualFile);
|
||||
}
|
||||
else {
|
||||
addVirtualFiles(virtualFile, readonly);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (virtualFile.getFileSystem() instanceof JarFileSystem) {
|
||||
failed.add(virtualFile);
|
||||
}
|
||||
else {
|
||||
readonly.add(virtualFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (element instanceof PsiCompiledElement) {
|
||||
final PsiFile file = element.getContainingFile();
|
||||
if (file != null) {
|
||||
failed.add(file.getVirtualFile());
|
||||
}
|
||||
}
|
||||
else {
|
||||
PsiFile file = element.getContainingFile();
|
||||
if (file == null) {
|
||||
if (!element.isWritable()) {
|
||||
seenNonWritablePsiFilesWithoutVirtualFile = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
final VirtualFile vFile = file.getVirtualFile();
|
||||
if (vFile != null) {
|
||||
readonly.add(vFile);
|
||||
}
|
||||
else {
|
||||
if (!element.isWritable()) {
|
||||
seenNonWritablePsiFilesWithoutVirtualFile = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final VirtualFile[] files = VfsUtil.toVirtualFileArray(readonly);
|
||||
final ReadonlyStatusHandler.OperationStatus status = ReadonlyStatusHandler.getInstance(project).ensureFilesWritable(files);
|
||||
ContainerUtil.addAll(failed, status.getReadonlyFiles());
|
||||
if (notifyOnFail && (!failed.isEmpty() || seenNonWritablePsiFilesWithoutVirtualFile && readonly.isEmpty())) {
|
||||
StringBuilder message = new StringBuilder(messagePrefix);
|
||||
message.append('\\n');
|
||||
int i = 0;
|
||||
for (VirtualFile virtualFile : failed) {
|
||||
final String presentableUrl = virtualFile.getPresentableUrl();
|
||||
final String subj = virtualFile.isDirectory()
|
||||
? RefactoringBundle.message("directory.description", presentableUrl)
|
||||
: RefactoringBundle.message("file.description", presentableUrl);
|
||||
if (virtualFile.getFileSystem() instanceof JarFileSystem) {
|
||||
message.append(RefactoringBundle.message("0.is.located.in.a.jar.file", subj));
|
||||
}
|
||||
else {
|
||||
message.append(RefactoringBundle.message("0.is.read.only", subj));
|
||||
}
|
||||
if (i++ > 20) {
|
||||
message.append("...\\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
showErrorMessage(RefactoringBundle.message("error.title"), message.toString(), null, project);
|
||||
return false;
|
||||
}
|
||||
|
||||
return failed.isEmpty();
|
||||
}
|
||||
|
||||
private static void addVirtualFiles(final VirtualFile vFile, final Collection<VirtualFile> list) {
|
||||
if (!vFile.isWritable()) {
|
||||
list.add(vFile);
|
||||
}
|
||||
if (!vFile.isSymLink()) {
|
||||
final VirtualFile[] children = vFile.getChildren();
|
||||
if (children != null) {
|
||||
final FileTypeManager fileTypeManager = FileTypeManager.getInstance();
|
||||
for (VirtualFile virtualFile : children) {
|
||||
if (fileTypeManager.isFileIgnored(virtualFile)) continue;
|
||||
addVirtualFiles(virtualFile, list);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String capitalize(String text) {
|
||||
return Character.toUpperCase(text.charAt(0)) + text.substring(1);
|
||||
}
|
||||
|
||||
public static boolean isAncestor(final PsiElement resolved, final Collection<? extends PsiElement> scopes) {
|
||||
for (final PsiElement scope : scopes) {
|
||||
if (PsiTreeUtil.isAncestor(scope, resolved, false)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
</selection>''', '''\
|
||||
<selection>/*
|
||||
* Copyright 2000-2011 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 com.intellij.refactoring.util
|
||||
|
||||
import com.intellij.codeInsight.hint.HintManager
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.fileTypes.FileTypeManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.JarFileSystem
|
||||
import com.intellij.openapi.vfs.ReadonlyStatusHandler
|
||||
import com.intellij.openapi.vfs.VfsUtil
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import com.intellij.refactoring.RefactoringBundle
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import gnu.trove.THashSet
|
||||
import org.jetbrains.annotations.NonNls
|
||||
import org.jetbrains.annotations.NotNull
|
||||
import org.jetbrains.annotations.Nullable
|
||||
|
||||
import java.util.Arrays
|
||||
import java.util.Collection
|
||||
import java.util.Collections
|
||||
|
||||
/**
|
||||
* @author ven
|
||||
*/
|
||||
public class CommonRefactoringUtil {
|
||||
private CommonRefactoringUtil() {}
|
||||
|
||||
public static void showErrorMessage(String title, String message, @Nullable @NonNls String helpId, @NotNull Project project) {
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) throw new RuntimeException(message)
|
||||
RefactoringMessageDialog dialog = new RefactoringMessageDialog(title, message, helpId, "OptionPane.errorIcon", false, project)
|
||||
dialog.show()
|
||||
}
|
||||
|
||||
/**
|
||||
* Fatal refactoring problem during unit test run. Corresponds to message of modal dialog shown during user driven refactoring.
|
||||
*/
|
||||
public static class RefactoringErrorHintException extends RuntimeException {
|
||||
public RefactoringErrorHintException(String message) {
|
||||
super(message)
|
||||
}
|
||||
}
|
||||
|
||||
public static void showErrorHint(Project project, @Nullable Editor editor, String message, String title, @Nullable @NonNls String helpId) {
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) throw new RefactoringErrorHintException(message)
|
||||
|
||||
if (editor == null) {
|
||||
showErrorMessage(title, message, helpId, project)
|
||||
}
|
||||
else {
|
||||
HintManager.getInstance().showErrorHint(editor, message)
|
||||
}
|
||||
}
|
||||
|
||||
@NonNls
|
||||
public static String htmlEmphasize(String text) {
|
||||
return "<b><code>" + text + "</code></b>"
|
||||
}
|
||||
|
||||
public static boolean checkReadOnlyStatus(@NotNull PsiElement element) {
|
||||
final VirtualFile file = element.getContainingFile().getVirtualFile()
|
||||
return file != null && !ReadonlyStatusHandler.getInstance(element.getProject()).ensureFilesWritable(file).hasReadonlyFiles()
|
||||
}
|
||||
|
||||
public static boolean checkReadOnlyStatus(@NotNull Project project, @NotNull PsiElement element) {
|
||||
return checkReadOnlyStatus(element, project, RefactoringBundle.message("refactoring.cannot.be.performed"))
|
||||
}
|
||||
|
||||
public static boolean checkReadOnlyStatus(@NotNull Project project, @NotNull PsiElement... elements) {
|
||||
return checkReadOnlyStatus(Arrays.asList(elements), project, RefactoringBundle.message("refactoring.cannot.be.performed"), false, true)
|
||||
}
|
||||
|
||||
public static boolean checkReadOnlyStatus(@NotNull PsiElement element, @NotNull Project project, String messagePrefix) {
|
||||
return element.isWritable() ||
|
||||
checkReadOnlyStatus(Collections.singleton(element), project, messagePrefix, false, true)
|
||||
}
|
||||
|
||||
public static boolean checkReadOnlyStatusRecursively(@NotNull Project project, @NotNull Collection<? extends PsiElement> elements) {
|
||||
return checkReadOnlyStatus(elements, project, RefactoringBundle.message("refactoring.cannot.be.performed"), true, false)
|
||||
}
|
||||
public static boolean checkReadOnlyStatusRecursively(@NotNull Project project, @NotNull Collection<? extends PsiElement> elements, boolean notifyOnFail) {
|
||||
return checkReadOnlyStatus(elements, project, RefactoringBundle.message("refactoring.cannot.be.performed"), true, notifyOnFail)
|
||||
}
|
||||
|
||||
private static boolean checkReadOnlyStatus(@NotNull Collection<? extends PsiElement> elements,
|
||||
@NotNull Project project,
|
||||
final String messagePrefix,
|
||||
boolean recursively,
|
||||
final boolean notifyOnFail) {
|
||||
final Collection<VirtualFile> readonly = new THashSet<VirtualFile>() // not writable, but could be checked out
|
||||
final Collection<VirtualFile> failed = new THashSet<VirtualFile>() // those located in jars
|
||||
boolean seenNonWritablePsiFilesWithoutVirtualFile = false
|
||||
|
||||
for (PsiElement element : elements) {
|
||||
if (element instanceof PsiDirectory) {
|
||||
final PsiDirectory dir = (PsiDirectory)element
|
||||
final VirtualFile vFile = dir.getVirtualFile()
|
||||
if (vFile.getFileSystem() instanceof JarFileSystem) {
|
||||
failed.add(vFile)
|
||||
}
|
||||
else {
|
||||
if (recursively) {
|
||||
addVirtualFiles(vFile, readonly)
|
||||
}
|
||||
else {
|
||||
readonly.add(vFile)
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (element instanceof PsiDirectoryContainer) {
|
||||
final PsiDirectory[] directories = ((PsiDirectoryContainer)element).getDirectories()
|
||||
for (PsiDirectory directory : directories) {
|
||||
VirtualFile virtualFile = directory.getVirtualFile()
|
||||
if (recursively) {
|
||||
if (virtualFile.getFileSystem() instanceof JarFileSystem) {
|
||||
failed.add(virtualFile)
|
||||
}
|
||||
else {
|
||||
addVirtualFiles(virtualFile, readonly)
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (virtualFile.getFileSystem() instanceof JarFileSystem) {
|
||||
failed.add(virtualFile)
|
||||
}
|
||||
else {
|
||||
readonly.add(virtualFile)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (element instanceof PsiCompiledElement) {
|
||||
final PsiFile file = element.getContainingFile()
|
||||
if (file != null) {
|
||||
failed.add(file.getVirtualFile())
|
||||
}
|
||||
}
|
||||
else {
|
||||
PsiFile file = element.getContainingFile()
|
||||
if (file == null) {
|
||||
if (!element.isWritable()) {
|
||||
seenNonWritablePsiFilesWithoutVirtualFile = true
|
||||
}
|
||||
}
|
||||
else {
|
||||
final VirtualFile vFile = file.getVirtualFile()
|
||||
if (vFile != null) {
|
||||
readonly.add(vFile)
|
||||
}
|
||||
else {
|
||||
if (!element.isWritable()) {
|
||||
seenNonWritablePsiFilesWithoutVirtualFile = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final VirtualFile[] files = VfsUtil.toVirtualFileArray(readonly)
|
||||
final ReadonlyStatusHandler.OperationStatus status = ReadonlyStatusHandler.getInstance(project).ensureFilesWritable(files)
|
||||
ContainerUtil.addAll(failed, status.getReadonlyFiles())
|
||||
if (notifyOnFail && (!failed.isEmpty() || seenNonWritablePsiFilesWithoutVirtualFile && readonly.isEmpty())) {
|
||||
StringBuilder message = new StringBuilder(messagePrefix)
|
||||
message.append('\\n')
|
||||
int i = 0
|
||||
for (VirtualFile virtualFile : failed) {
|
||||
final String presentableUrl = virtualFile.getPresentableUrl()
|
||||
final String subj = virtualFile.isDirectory()
|
||||
? RefactoringBundle.message("directory.description", presentableUrl)
|
||||
: RefactoringBundle.message("file.description", presentableUrl)
|
||||
if (virtualFile.getFileSystem() instanceof JarFileSystem) {
|
||||
message.append(RefactoringBundle.message("0.is.located.in.a.jar.file", subj))
|
||||
}
|
||||
else {
|
||||
message.append(RefactoringBundle.message("0.is.read.only", subj))
|
||||
}
|
||||
if (i++ > 20) {
|
||||
message.append("...\\n")
|
||||
break
|
||||
}
|
||||
}
|
||||
showErrorMessage(RefactoringBundle.message("error.title"), message.toString(), null, project)
|
||||
return false
|
||||
}
|
||||
|
||||
return failed.isEmpty()
|
||||
}
|
||||
|
||||
private static void addVirtualFiles(final VirtualFile vFile, final Collection<VirtualFile> list) {
|
||||
if (!vFile.isWritable()) {
|
||||
list.add(vFile)
|
||||
}
|
||||
if (!vFile.isSymLink()) {
|
||||
final VirtualFile[] children = vFile.getChildren()
|
||||
if (children != null) {
|
||||
final FileTypeManager fileTypeManager = FileTypeManager.getInstance()
|
||||
for (VirtualFile virtualFile : children) {
|
||||
if (fileTypeManager.isFileIgnored(virtualFile)) continue
|
||||
addVirtualFiles(virtualFile, list)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String capitalize(String text) {
|
||||
return Character.toUpperCase(text.charAt(0)) + text.substring(1)
|
||||
}
|
||||
|
||||
public static boolean isAncestor(final PsiElement resolved, final Collection<? extends PsiElement> scopes) {
|
||||
for (final PsiElement scope : scopes) {
|
||||
if (PsiTreeUtil.isAncestor(scope, resolved, false)) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
</selection>''')
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user