mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -83,6 +83,9 @@ public class AddTypeCastFix extends LocalQuickFixAndIntentionActionOnPsiElement
|
||||
static PsiExpression createCastExpression(PsiExpression originalExpression, Project project, PsiType type) throws IncorrectOperationException {
|
||||
// remove nested casts
|
||||
PsiElement element = PsiUtil.deparenthesizeExpression(originalExpression);
|
||||
if (element == null){
|
||||
return null;
|
||||
}
|
||||
PsiElementFactory factory = JavaPsiFacade.getInstance(originalExpression.getProject()).getElementFactory();
|
||||
|
||||
PsiTypeCastExpression typeCast = (PsiTypeCastExpression)factory.createExpressionFromText("(Type)value", null);
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.intellij.lang.Language;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.ref.SoftReference;
|
||||
|
||||
@@ -31,23 +32,27 @@ public class PsiInvalidElementAccessException extends RuntimeException {
|
||||
private final SoftReference<PsiElement> myElementReference; // to prevent leaks, since exceptions are stored in IdeaLogger
|
||||
|
||||
public PsiInvalidElementAccessException(PsiElement element) {
|
||||
this(element, null, null);
|
||||
this(element, (String)null);
|
||||
}
|
||||
|
||||
public PsiInvalidElementAccessException(PsiElement element, String message) {
|
||||
this(element, message, null);
|
||||
public PsiInvalidElementAccessException(PsiElement element, @Nullable String message) {
|
||||
this(element, getMessageWithReason(element, message), null);
|
||||
}
|
||||
|
||||
public PsiInvalidElementAccessException(PsiElement element, Throwable cause) {
|
||||
this(element, null, cause);
|
||||
public PsiInvalidElementAccessException(PsiElement element, @Nullable Throwable cause) {
|
||||
this(element, getMessageWithReason(element, null), cause);
|
||||
}
|
||||
|
||||
public PsiInvalidElementAccessException(PsiElement element, String message, Throwable cause) {
|
||||
super((element != null ? "Element: " + element.getClass() + " because: " + reason(element) : "Unknown psi element") +
|
||||
(message == null ? "" : "; " + message), cause);
|
||||
public PsiInvalidElementAccessException(PsiElement element, @Nullable String message, @Nullable Throwable cause) {
|
||||
super(message, cause);
|
||||
myElementReference = new SoftReference<PsiElement>(element);
|
||||
}
|
||||
|
||||
private static String getMessageWithReason(@Nullable PsiElement element, @Nullable String message) {
|
||||
return (element != null ? "Element: " + element.getClass() + " because: " + reason(element) : "Unknown psi element") +
|
||||
(message == null ? "" : "; " + message);
|
||||
}
|
||||
|
||||
@NonNls
|
||||
@NotNull
|
||||
private static String reason(@NotNull PsiElement root){
|
||||
@@ -71,6 +76,7 @@ public class PsiInvalidElementAccessException extends RuntimeException {
|
||||
return "psi is outdated";
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PsiElement getPsiElement() {
|
||||
return myElementReference.get();
|
||||
}
|
||||
|
||||
@@ -144,7 +144,7 @@ public class StubBasedPsiElementBase<T extends StubElement> extends ASTDelegateP
|
||||
}
|
||||
PsiFile psi = (PsiFile)stub.getPsi();
|
||||
if (psi == null) {
|
||||
throw new PsiInvalidElementAccessException(this);
|
||||
throw new PsiInvalidElementAccessException(this, "no psi for file stub " + stub, null);
|
||||
}
|
||||
return psi;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.intellij.codeEditor.printing;
|
||||
|
||||
import com.intellij.CommonBundle;
|
||||
import com.intellij.ide.highlighter.HighlighterFactory;
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.actionSystem.LangDataKeys;
|
||||
@@ -28,12 +29,14 @@ import com.intellij.openapi.editor.highlighter.EditorHighlighter;
|
||||
import com.intellij.openapi.fileTypes.FileTypes;
|
||||
import com.intellij.openapi.progress.*;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.psi.PsiDirectory;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.print.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@@ -151,8 +154,14 @@ class PrintManager {
|
||||
|
||||
printerJob.print();
|
||||
}
|
||||
catch(PrinterException e) {
|
||||
LOG.error(e);
|
||||
catch(final PrinterException e) {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Messages.showErrorDialog(project, e.getMessage(), CommonBundle.getErrorTitle());
|
||||
}
|
||||
});
|
||||
LOG.info(e);
|
||||
}
|
||||
catch(ProcessCanceledException e) {
|
||||
printerJob.cancel();
|
||||
|
||||
+6
-6
@@ -25,14 +25,9 @@ import com.intellij.openapi.editor.actionSystem.EditorActionHandler;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiWhiteSpace;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.util.Processor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class UnSelectWordHandler extends EditorActionHandler {
|
||||
private final EditorActionHandler myOriginalHandler;
|
||||
|
||||
@@ -59,6 +54,11 @@ public class UnSelectWordHandler extends EditorActionHandler {
|
||||
|
||||
|
||||
private static void doAction(Editor editor, PsiFile file) {
|
||||
if (file instanceof PsiCompiledFile) {
|
||||
file = ((PsiCompiledFile)file).getDecompiledPsiFile();
|
||||
if (file == null) return;
|
||||
}
|
||||
|
||||
if (!editor.getSelectionModel().hasSelection()) {
|
||||
return;
|
||||
}
|
||||
|
||||
+2
@@ -55,6 +55,7 @@ public final class StructureViewFactoryImpl extends StructureViewFactoryEx imple
|
||||
@SuppressWarnings({"WeakerAccess"}) public boolean AUTOSCROLL_MODE = true;
|
||||
@SuppressWarnings({"WeakerAccess"}) public boolean AUTOSCROLL_FROM_SOURCE = false;
|
||||
@SuppressWarnings({"WeakerAccess"}) public String ACTIVE_ACTIONS = "";
|
||||
public boolean SHOW_TOOLBAR = false;
|
||||
}
|
||||
|
||||
private final Project myProject;
|
||||
@@ -85,6 +86,7 @@ public final class StructureViewFactoryImpl extends StructureViewFactoryEx imple
|
||||
return myStructureViewWrapperImpl;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public State getState() {
|
||||
return myState;
|
||||
}
|
||||
|
||||
+32
-11
@@ -154,6 +154,10 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre
|
||||
myAutoScrollToSourceHandler = new MyAutoScrollToSourceHandler();
|
||||
myAutoScrollFromSourceHandler = new MyAutoScrollFromSourceHandler(myProject, this);
|
||||
|
||||
if (getSettings().SHOW_TOOLBAR) {
|
||||
setToolbar(createToolbar());
|
||||
}
|
||||
|
||||
installTree();
|
||||
|
||||
myCopyPasteDelegator = new CopyPasteDelegator(myProject, getTree()) {
|
||||
@@ -164,6 +168,10 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre
|
||||
};
|
||||
}
|
||||
|
||||
private JComponent createToolbar() {
|
||||
return ActionManager.getInstance().createActionToolbar(ActionPlaces.STRUCTURE_VIEW_TOOLBAR, createActionGroup(), true).getComponent();
|
||||
}
|
||||
|
||||
private void installTree() {
|
||||
getTree().getSelectionModel().setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
|
||||
myAutoScrollToSourceHandler.install(getTree());
|
||||
@@ -367,7 +375,24 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre
|
||||
}
|
||||
|
||||
public ActionGroup getGearActions() {
|
||||
return createActionGroup(true);
|
||||
DefaultActionGroup group = createActionGroup(true);
|
||||
group.addAction(new ToggleAction("Show Toolbar") {
|
||||
@Override
|
||||
public boolean isSelected(AnActionEvent e) {
|
||||
return getSettings().SHOW_TOOLBAR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelected(AnActionEvent e, boolean state) {
|
||||
setToolbar(state ? createToolbar() : null);
|
||||
getSettings().SHOW_TOOLBAR = state;
|
||||
}
|
||||
}).setAsSecondary(true);
|
||||
return group;
|
||||
}
|
||||
|
||||
private StructureViewFactoryImpl.State getSettings() {
|
||||
return ((StructureViewFactoryImpl)StructureViewFactory.getInstance(myProject)).getState();
|
||||
}
|
||||
|
||||
public AnAction[] getTitleActions() {
|
||||
@@ -381,7 +406,7 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre
|
||||
return createActionGroup(false);
|
||||
}
|
||||
|
||||
protected ActionGroup createActionGroup(boolean togglesOnly) {
|
||||
protected DefaultActionGroup createActionGroup(boolean togglesOnly) {
|
||||
DefaultActionGroup result = new DefaultActionGroup();
|
||||
Sorter[] sorters = myTreeModel.getSorters();
|
||||
for (final Sorter sorter : sorters) {
|
||||
@@ -522,9 +547,7 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre
|
||||
return;
|
||||
}
|
||||
|
||||
StructureViewFactoryImpl structureViewFactory = (StructureViewFactoryImpl)StructureViewFactoryEx.getInstance(myProject);
|
||||
|
||||
if (!structureViewFactory.getState().AUTOSCROLL_FROM_SOURCE) {
|
||||
if (!getSettings().AUTOSCROLL_FROM_SOURCE) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -612,11 +635,11 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre
|
||||
|
||||
protected boolean isAutoScrollMode() {
|
||||
return myShouldAutoScroll && !myProject.isDisposed()
|
||||
&& ((StructureViewFactoryImpl)StructureViewFactory.getInstance(myProject)).getState().AUTOSCROLL_MODE;
|
||||
&& getSettings().AUTOSCROLL_MODE;
|
||||
}
|
||||
|
||||
protected void setAutoScrollMode(boolean state) {
|
||||
((StructureViewFactoryImpl)StructureViewFactory.getInstance(myProject)).getState().AUTOSCROLL_MODE = state;
|
||||
getSettings().AUTOSCROLL_MODE = state;
|
||||
}
|
||||
|
||||
protected void scrollToSource(Component tree) {
|
||||
@@ -659,13 +682,11 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre
|
||||
}
|
||||
|
||||
protected boolean isAutoScrollEnabled() {
|
||||
StructureViewFactoryImpl structureViewFactory = (StructureViewFactoryImpl)StructureViewFactory.getInstance(myProject);
|
||||
return structureViewFactory.getState().AUTOSCROLL_FROM_SOURCE;
|
||||
return getSettings().AUTOSCROLL_FROM_SOURCE;
|
||||
}
|
||||
|
||||
protected void setAutoScrollEnabled(boolean state) {
|
||||
StructureViewFactoryImpl structureViewFactory = (StructureViewFactoryImpl)StructureViewFactory.getInstance(myProject);
|
||||
structureViewFactory.getState().AUTOSCROLL_FROM_SOURCE = state;
|
||||
getSettings().AUTOSCROLL_FROM_SOURCE = state;
|
||||
final FileEditor[] selectedEditors = FileEditorManager.getInstance(myProject).getSelectedEditors();
|
||||
if (selectedEditors.length > 0 && state) {
|
||||
scrollToSelectedElement();
|
||||
|
||||
@@ -4,7 +4,6 @@ package com.intellij.openapi.paths;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.ElementManipulator;
|
||||
import com.intellij.psi.ElementManipulators;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiReference;
|
||||
@@ -21,9 +20,7 @@ public abstract class PathReferenceProviderBase implements PathReferenceProvider
|
||||
|
||||
public boolean createReferences(@NotNull final PsiElement psiElement, final @NotNull List<PsiReference> references, final boolean soft) {
|
||||
|
||||
final ElementManipulator<PsiElement> manipulator = ElementManipulators.getManipulator(psiElement);
|
||||
assert manipulator != null;
|
||||
final TextRange range = manipulator.getRangeInElement(psiElement);
|
||||
final TextRange range = ElementManipulators.getValueTextRange(psiElement);
|
||||
int offset = range.getStartOffset();
|
||||
int endOffset = range.getEndOffset();
|
||||
final String elementText = psiElement.getText();
|
||||
|
||||
@@ -74,13 +74,18 @@ public class SimpleToolWindowPanel extends JPanel implements QuickActionProvider
|
||||
});
|
||||
}
|
||||
|
||||
public void setToolbar(JComponent c) {
|
||||
public void setToolbar(@Nullable JComponent c) {
|
||||
if (c == null) {
|
||||
remove(myToolbar);
|
||||
}
|
||||
myToolbar = c;
|
||||
|
||||
if (myVertical) {
|
||||
add(c, BorderLayout.NORTH);
|
||||
} else {
|
||||
add(c, BorderLayout.WEST);
|
||||
if (c != null) {
|
||||
if (myVertical) {
|
||||
add(c, BorderLayout.NORTH);
|
||||
} else {
|
||||
add(c, BorderLayout.WEST);
|
||||
}
|
||||
}
|
||||
|
||||
revalidate();
|
||||
|
||||
@@ -754,7 +754,7 @@ public final class TreeUtil {
|
||||
|
||||
@NotNull
|
||||
public static ArrayList<TreeNode> childrenToArray(@NotNull final TreeNode node) {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
//ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
final ArrayList<TreeNode> result = new ArrayList<TreeNode>();
|
||||
for(int i = 0; i < node.getChildCount(); i++){
|
||||
TreeNode child = node.getChildAt(i);
|
||||
|
||||
+30
-20
@@ -39,6 +39,7 @@ import com.intellij.openapi.editor.ex.EditorSettingsExternalizable;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.fileChooser.FileChooserFactory;
|
||||
import com.intellij.openapi.fileChooser.FileSaverDescriptor;
|
||||
import com.intellij.openapi.fileChooser.FileSaverDialog;
|
||||
import com.intellij.openapi.fileEditor.*;
|
||||
import com.intellij.openapi.fileEditor.impl.text.TextEditorImpl;
|
||||
import com.intellij.openapi.fileTypes.BinaryFileTypeDecompilers;
|
||||
@@ -430,33 +431,42 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl
|
||||
@Nullable
|
||||
private static VirtualFile handleExternalDeletion(VirtualFile file) {
|
||||
String path = file.getPath();
|
||||
String[] options = {"Restore", "Save under a different name", "Discard changes"};
|
||||
int result = suggestToRestoreDeletedFile(path, new String[]{"Restore", "Save under a different name", "Discard changes"});
|
||||
if (result == 0) return createFile(new File(path));
|
||||
if (result == 1) return saveUnderDifferentName(file);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static VirtualFile saveUnderDifferentName(VirtualFile file) {
|
||||
FileSaverDescriptor descriptor = new FileSaverDescriptor("Save File As...", "Save file under a different name");
|
||||
FileSaverDialog dialog = FileChooserFactory.getInstance().createSaveFileDialog(descriptor, (Project)null);
|
||||
VirtualFileWrapper wrapper = dialog.save(findValidParent(file), file.getName());
|
||||
return wrapper == null ? null : createFile(wrapper.getFile());
|
||||
}
|
||||
|
||||
private static int suggestToRestoreDeletedFile(String path, String[] options) {
|
||||
String message = "File has been deleted on disk: " + FileUtil.toSystemDependentName(path);
|
||||
int result = Messages.showDialog(message, "File Deleted", options, 0, Messages.getQuestionIcon());
|
||||
File newFile;
|
||||
if (result == 0) {
|
||||
newFile = new File(path);
|
||||
} else if (result == 1) {
|
||||
VirtualFile validParent = file;
|
||||
while (validParent != null && !validParent.isValid()) {
|
||||
validParent = validParent.getParent();
|
||||
}
|
||||
final VirtualFileWrapper wrapper = FileChooserFactory.getInstance().createSaveFileDialog(
|
||||
new FileSaverDescriptor("Save File As...", "Save file under a different name"), (Project)null).save(validParent, file.getName());
|
||||
if (wrapper == null) {
|
||||
return null;
|
||||
}
|
||||
newFile = wrapper.getFile();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return Messages.showDialog(message, "File Deleted", options, 0, Messages.getQuestionIcon());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static VirtualFile createFile(File newFile) {
|
||||
if (!FileUtil.createIfDoesntExist(newFile)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return LocalFileSystem.getInstance().refreshAndFindFileByIoFile(newFile);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static VirtualFile findValidParent(VirtualFile file) {
|
||||
VirtualFile validParent = file;
|
||||
while (validParent != null && !validParent.isValid()) {
|
||||
validParent = validParent.getParent();
|
||||
}
|
||||
return validParent;
|
||||
}
|
||||
|
||||
private static void updateModifiedProperty(@NotNull VirtualFile file) {
|
||||
for (Project project : ProjectManager.getInstance().getOpenProjects()) {
|
||||
FileEditorManager fileEditorManager = FileEditorManager.getInstance(project);
|
||||
|
||||
@@ -440,6 +440,6 @@
|
||||
<daemon.changeLocalityDetector implementation="com.intellij.xml.XmlChangeLocalityDetector"/>
|
||||
</extensions>
|
||||
<extensions defaultExtensionNs="org.jetbrains">
|
||||
<urlOpener implementation="com.intellij.ide.browsers.impl.UrlOpenerImpl" order="last"/>
|
||||
<urlOpener implementation="com.intellij.ide.browsers.impl.DefaultUrlOpener" order="last"/>
|
||||
</extensions>
|
||||
</idea-plugin>
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
print <spot>String</spot>
|
||||
+1
@@ -0,0 +1 @@
|
||||
print <spot>String.class</spot>
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
This intention removes redundant explicit .class reference.
|
||||
</body>
|
||||
</html>
|
||||
@@ -1178,6 +1178,11 @@
|
||||
<categoryKey>intention.category.groovy/intention.category.groovy.style</categoryKey>
|
||||
<className>org.jetbrains.plugins.groovy.intentions.style.ConvertToGeeseBracesIntention</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.RemoveRedundantClassPropertyIntention</className>
|
||||
</intentionAction>
|
||||
<intentionAction>
|
||||
<bundleName>org.jetbrains.plugins.groovy.intentions.GroovyIntentionsBundle</bundleName>
|
||||
<categoryKey>intention.category.groovy/intention.category.groovy.style</categoryKey>
|
||||
|
||||
+3
-1
@@ -173,4 +173,6 @@ remove.unnecessary.escape.characters.intention.family.name=Remove unnecessary es
|
||||
gr.break.string.on.line.breaks.intention.name=Break string on '\\n'
|
||||
gr.break.string.on.line.breaks.intention.family.name=Break string on '\\n'
|
||||
gr.create.missing.switch.branches.intention.name=Create missing 'switch' branches
|
||||
gr.create.missing.switch.branches.intention.family.name=Create missing 'switch' branches
|
||||
gr.create.missing.switch.branches.intention.family.name=Create missing 'switch' branches
|
||||
remove.redundant.class.property.intention.name=Remove redundant .class
|
||||
remove.redundant.class.property.intention.family.name=Remove redundant .class
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2000-2012 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.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.plugins.groovy.intentions.base.Intention;
|
||||
import org.jetbrains.plugins.groovy.intentions.base.PsiElementPredicate;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
|
||||
|
||||
/**
|
||||
* @author Max Medvedev
|
||||
*/
|
||||
public class RemoveRedundantClassPropertyIntention extends Intention {
|
||||
@Override
|
||||
protected void processIntention(@NotNull PsiElement element, Project project, Editor editor) throws IncorrectOperationException {
|
||||
if (element instanceof GrReferenceExpression) {
|
||||
((GrReferenceExpression)element).replaceWithExpression(((GrReferenceExpression)element).getQualifier(), true);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected PsiElementPredicate getElementPredicate() {
|
||||
return new PsiElementPredicate() {
|
||||
@Override
|
||||
public boolean satisfiedBy(PsiElement element) {
|
||||
if (element instanceof GrReferenceExpression && "class".equals(((GrReferenceExpression)element).getReferenceName())) {
|
||||
GrExpression qualifier = ((GrReferenceExpression)element).getQualifier();
|
||||
if (qualifier instanceof GrReferenceExpression) {
|
||||
return ((GrReferenceExpression)qualifier).resolve() instanceof PsiClass;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
+123
-53
@@ -23,18 +23,16 @@ import gnu.trove.TIntObjectProcedure;
|
||||
import gnu.trove.TIntProcedure;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GrControlFlowOwner;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyRecursiveElementVisitor;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrClassInitializer;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMember;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.controlFlow.ControlFlowBuilderUtil;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.controlFlow.ReadWriteVariableInstruction;
|
||||
@@ -55,19 +53,13 @@ public class ReachingDefinitionsCollector {
|
||||
|
||||
@NotNull
|
||||
public static FragmentVariableInfos obtainVariableFlowInformation(final GrStatement first, final GrStatement last) {
|
||||
GroovyPsiElement context = PsiTreeUtil.getParentOfType(first, GrMethod.class, GrClosableBlock.class, GroovyFileBase.class, GrClassInitializer.class);
|
||||
GrControlFlowOwner flowOwner;
|
||||
if (context instanceof GrMethod) flowOwner = ((GrMethod) context).getBlock();
|
||||
else flowOwner = (GrControlFlowOwner) context;
|
||||
GrControlFlowOwner flowOwner = ControlFlowUtils.findControlFlowOwner(first);
|
||||
|
||||
assert flowOwner != null;
|
||||
assert PsiTreeUtil.isAncestor(flowOwner, last, true);
|
||||
|
||||
final Instruction[] flow = flowOwner.getControlFlow();
|
||||
final ReachingDefinitionsDfaInstance dfaInstance = new ReachingDefinitionsDfaInstance(flow);
|
||||
final ReachingDefinitionsSemilattice lattice = new ReachingDefinitionsSemilattice();
|
||||
final DFAEngine<DefinitionMap> engine = new DFAEngine<DefinitionMap>(flow, dfaInstance, lattice);
|
||||
final DefinitionMap dfaResult = postprocess(engine.performForceDFA(), flow, dfaInstance);
|
||||
final DefinitionMap dfaResult = inferDfaResult(flow);
|
||||
|
||||
final LinkedHashSet<Integer> fragmentInstructions = getFragmentInstructions(first, last, flow);
|
||||
final int[] postorder = ControlFlowBuilderUtil.postorder(flow);
|
||||
@@ -80,7 +72,7 @@ public class ReachingDefinitionsCollector {
|
||||
final PsiManager manager = first.getManager();
|
||||
|
||||
for (final Integer ref : fragmentReads) {
|
||||
ReadWriteVariableInstruction rwInstruction = (ReadWriteVariableInstruction) flow[ref];
|
||||
ReadWriteVariableInstruction rwInstruction = (ReadWriteVariableInstruction)flow[ref];
|
||||
String name = rwInstruction.getVariableName();
|
||||
final int[] defs = dfaResult.getDefinitions(ref);
|
||||
if (!allDefsInFragment(defs, fragmentInstructions)) {
|
||||
@@ -89,22 +81,22 @@ public class ReachingDefinitionsCollector {
|
||||
}
|
||||
|
||||
for (final Integer ref : reachableFromFragmentReads) {
|
||||
ReadWriteVariableInstruction rwInstruction = (ReadWriteVariableInstruction) flow[ref];
|
||||
String name = rwInstruction.getVariableName();
|
||||
final int[] defs = dfaResult.getDefinitions(ref);
|
||||
if (anyDefInFragment(defs, fragmentInstructions)) {
|
||||
for (int def : defs) {
|
||||
if (fragmentInstructions.contains(def)) {
|
||||
PsiType outputType = getType(flow[def].getElement());
|
||||
addVariable(name, omap, manager, outputType);
|
||||
}
|
||||
}
|
||||
|
||||
if (!allProperDefsInFragment(defs, ref, fragmentInstructions, postorder)) {
|
||||
PsiType inputType = getType(rwInstruction.getElement());
|
||||
addVariable(name, imap, manager, inputType);
|
||||
ReadWriteVariableInstruction rwInstruction = (ReadWriteVariableInstruction)flow[ref];
|
||||
String name = rwInstruction.getVariableName();
|
||||
final int[] defs = dfaResult.getDefinitions(ref);
|
||||
if (anyDefInFragment(defs, fragmentInstructions)) {
|
||||
for (int def : defs) {
|
||||
if (fragmentInstructions.contains(def)) {
|
||||
PsiType outputType = getType(flow[def].getElement());
|
||||
addVariable(name, omap, manager, outputType);
|
||||
}
|
||||
}
|
||||
|
||||
if (!allProperDefsInFragment(defs, ref, fragmentInstructions, postorder)) {
|
||||
PsiType inputType = getType(rwInstruction.getElement());
|
||||
addVariable(name, imap, manager, inputType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addClosureUsages(imap, omap, first, last, flowOwner);
|
||||
@@ -123,14 +115,29 @@ public class ReachingDefinitionsCollector {
|
||||
};
|
||||
}
|
||||
|
||||
private static void addClosureUsages(final Map<String, VariableInfo> imap, final Map<String, VariableInfo> omap, final GrStatement first, final GrStatement last, GrControlFlowOwner flowOwner) {
|
||||
private static DefinitionMap inferDfaResult(Instruction[] flow) {
|
||||
final ReachingDefinitionsDfaInstance dfaInstance = new ReachingDefinitionsDfaInstance(flow);
|
||||
final ReachingDefinitionsSemilattice lattice = new ReachingDefinitionsSemilattice();
|
||||
final DFAEngine<DefinitionMap> engine = new DFAEngine<DefinitionMap>(flow, dfaInstance, lattice);
|
||||
return postprocess(engine.performForceDFA(), flow, dfaInstance);
|
||||
}
|
||||
|
||||
private static void addClosureUsages(final Map<String, VariableInfo> imap,
|
||||
final Map<String, VariableInfo> omap,
|
||||
final GrStatement first,
|
||||
final GrStatement last,
|
||||
GrControlFlowOwner flowOwner) {
|
||||
flowOwner.accept(new GroovyRecursiveElementVisitor() {
|
||||
public void visitClosure(GrClosableBlock closure) {
|
||||
addUsagesInClosure(imap, omap, closure, first, last);
|
||||
super.visitClosure(closure);
|
||||
}
|
||||
|
||||
private void addUsagesInClosure(final Map<String, VariableInfo> imap, final Map<String, VariableInfo> omap, final GrClosableBlock closure, final GrStatement first, final GrStatement last) {
|
||||
private void addUsagesInClosure(final Map<String, VariableInfo> imap,
|
||||
final Map<String, VariableInfo> omap,
|
||||
final GrClosableBlock closure,
|
||||
final GrStatement first,
|
||||
final GrStatement last) {
|
||||
closure.accept(new GroovyRecursiveElementVisitor() {
|
||||
public void visitReferenceExpression(GrReferenceExpression refExpr) {
|
||||
if (refExpr.isQualified()) {
|
||||
@@ -140,7 +147,7 @@ public class ReachingDefinitionsCollector {
|
||||
if (!(resolved instanceof GrVariable)) {
|
||||
return;
|
||||
}
|
||||
GrVariable variable = (GrVariable) resolved;
|
||||
GrVariable variable = (GrVariable)resolved;
|
||||
if (PsiTreeUtil.isAncestor(closure, variable, true)) {
|
||||
return;
|
||||
}
|
||||
@@ -169,7 +176,7 @@ public class ReachingDefinitionsCollector {
|
||||
}
|
||||
|
||||
private static void addVariable(String name, Map<String, VariableInfo> map, PsiManager manager, PsiType type) {
|
||||
VariableInfoImpl info = (VariableInfoImpl) map.get(name);
|
||||
VariableInfoImpl info = (VariableInfoImpl)map.get(name);
|
||||
if (info == null) {
|
||||
info = new VariableInfoImpl(name, manager);
|
||||
map.put(name, info);
|
||||
@@ -181,7 +188,7 @@ public class ReachingDefinitionsCollector {
|
||||
final LinkedHashSet<Integer> result = new LinkedHashSet<Integer>();
|
||||
for (final Integer i : instructions) {
|
||||
final Instruction instruction = flow[i];
|
||||
if (instruction instanceof ReadWriteVariableInstruction && !((ReadWriteVariableInstruction) instruction).isWrite()) {
|
||||
if (isReadInsn(instruction)) {
|
||||
result.add(i);
|
||||
}
|
||||
}
|
||||
@@ -215,21 +222,27 @@ public class ReachingDefinitionsCollector {
|
||||
|
||||
@Nullable
|
||||
private static PsiType getType(PsiElement element) {
|
||||
if (element instanceof GrVariable) return ((GrVariable) element).getTypeGroovy();
|
||||
else if (element instanceof GrReferenceExpression) return ((GrReferenceExpression) element).getType();
|
||||
if (element instanceof GrVariable) {
|
||||
return ((GrVariable)element).getTypeGroovy();
|
||||
}
|
||||
else if (element instanceof GrReferenceExpression) return ((GrReferenceExpression)element).getType();
|
||||
return null;
|
||||
}
|
||||
|
||||
private static VariableInfo[] filterNonlocals(Map<String, VariableInfo> infos, GrStatement place) {
|
||||
List<VariableInfo> result = new ArrayList<VariableInfo>();
|
||||
for (Iterator<VariableInfo> iterator = infos.values().iterator(); iterator.hasNext();) {
|
||||
for (Iterator<VariableInfo> iterator = infos.values().iterator(); iterator.hasNext(); ) {
|
||||
VariableInfo info = iterator.next();
|
||||
String name = info.getName();
|
||||
GroovyPsiElement property = ResolveUtil.resolveProperty(place, name);
|
||||
if (property instanceof GrVariable) iterator.remove();
|
||||
if (property instanceof GrVariable) {
|
||||
iterator.remove();
|
||||
}
|
||||
else if (property instanceof GrReferenceExpression) {
|
||||
GrMember member = PsiTreeUtil.getParentOfType(property, GrMember.class);
|
||||
if (member == null) continue;
|
||||
if (member == null) {
|
||||
continue;
|
||||
}
|
||||
else if (!member.hasModifierProperty(PsiModifier.STATIC)) {
|
||||
if (member.getContainingClass() instanceof GroovyScriptClass) {
|
||||
//binding variable
|
||||
@@ -277,20 +290,20 @@ public class ReachingDefinitionsCollector {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static LinkedHashSet<Integer> getReachable(final LinkedHashSet<Integer> fragmentInsns, final Instruction[] flow, DefinitionMap dfaResult, final int[] postorder) {
|
||||
private static LinkedHashSet<Integer> getReachable(final LinkedHashSet<Integer> fragmentInsns,
|
||||
final Instruction[] flow,
|
||||
final DefinitionMap dfaResult,
|
||||
final int[] postorder) {
|
||||
final LinkedHashSet<Integer> result = new LinkedHashSet<Integer>();
|
||||
for (Instruction insn : flow) {
|
||||
if (insn instanceof ReadWriteVariableInstruction &&
|
||||
!((ReadWriteVariableInstruction) insn).isWrite()) {
|
||||
for (final Instruction insn : flow) {
|
||||
if (isReadInsn(insn)) {
|
||||
final int ref = insn.num();
|
||||
for (int def : dfaResult.getDefinitions(ref)) {
|
||||
if (fragmentInsns.contains(def)) {
|
||||
if (!fragmentInsns.contains(ref) || postorder[ref] < postorder[def]) {
|
||||
result.add(ref);
|
||||
break;
|
||||
}
|
||||
for (final int def : dfaResult.getDefinitions(ref)) {
|
||||
if (fragmentInsns.contains(def) &&
|
||||
(!fragmentInsns.contains(ref) || postorder[ref] < postorder[def] && checkPathIsOutsideOfFragment(def, ref, flow, fragmentInsns))) {
|
||||
result.add(ref);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -298,6 +311,60 @@ public class ReachingDefinitionsCollector {
|
||||
return result;
|
||||
}
|
||||
|
||||
private static boolean checkPathIsOutsideOfFragment(int def, int ref, Instruction[] flow, LinkedHashSet<Integer> fragmentInsns) {
|
||||
Boolean path = findPath(flow[def], ref, fragmentInsns, false, new HashMap<Instruction, Boolean>());
|
||||
assert path != null : "def=" + def + ", ref=" + ref;
|
||||
return path.booleanValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* return true if path is outside of fragment, null if there is no pathand false if path is inside fragment
|
||||
*/
|
||||
@Nullable
|
||||
private static Boolean findPath(Instruction cur,
|
||||
int destination,
|
||||
LinkedHashSet<Integer> fragmentInsns,
|
||||
boolean wasOutside,
|
||||
HashMap<Instruction, Boolean> visited) {
|
||||
wasOutside = wasOutside || !fragmentInsns.contains(cur.num());
|
||||
visited.put(cur, null);
|
||||
Iterable<? extends Instruction> instructions = cur.allSuccessors();
|
||||
|
||||
boolean pathExists = false;
|
||||
for (Instruction i : instructions) {
|
||||
if (i.num() == destination) return wasOutside;
|
||||
|
||||
Boolean result;
|
||||
if (visited.containsKey(i)) {
|
||||
result = visited.get(i);
|
||||
}
|
||||
else {
|
||||
result = findPath(i, destination, fragmentInsns, wasOutside, visited);
|
||||
visited.put(i, result);
|
||||
}
|
||||
if (result != null) {
|
||||
if (result.booleanValue()) {
|
||||
visited.put(cur, true);
|
||||
return true;
|
||||
}
|
||||
pathExists = true;
|
||||
}
|
||||
}
|
||||
if (pathExists) {
|
||||
visited.put(cur, false);
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
visited.put(cur, null);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static boolean isReadInsn(Instruction insn) {
|
||||
return insn instanceof ReadWriteVariableInstruction && !((ReadWriteVariableInstruction)insn).isWrite();
|
||||
}
|
||||
|
||||
@SuppressWarnings({"UnusedDeclaration"})
|
||||
private static String dumpDfaResult(ArrayList<TIntObjectHashMap<TIntHashSet>> dfaResult, ReachingDefinitionsDfaInstance dfa) {
|
||||
final StringBuffer buffer = new StringBuffer();
|
||||
@@ -343,18 +410,21 @@ public class ReachingDefinitionsCollector {
|
||||
|
||||
@Nullable
|
||||
public PsiType getType() {
|
||||
if (myType instanceof PsiIntersectionType) return ((PsiIntersectionType) myType).getConjuncts()[0];
|
||||
if (myType instanceof PsiIntersectionType) return ((PsiIntersectionType)myType).getConjuncts()[0];
|
||||
return myType;
|
||||
}
|
||||
|
||||
void addSubtype(PsiType t) {
|
||||
if (t != null) {
|
||||
if (myType == null) myType = t;
|
||||
if (myType == null) {
|
||||
myType = t;
|
||||
}
|
||||
else {
|
||||
if (!myType.isAssignableFrom(t)) {
|
||||
if (t.isAssignableFrom(myType)) {
|
||||
myType = t;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
myType = TypesUtil.getLeastUpperBound(myType, t, myManager);
|
||||
}
|
||||
}
|
||||
@@ -365,13 +435,13 @@ public class ReachingDefinitionsCollector {
|
||||
|
||||
@NotNull
|
||||
private static DefinitionMap postprocess(@NotNull final ArrayList<DefinitionMap> dfaResult,
|
||||
@NotNull Instruction[] flow,
|
||||
@NotNull ReachingDefinitionsDfaInstance dfaInstance) {
|
||||
@NotNull Instruction[] flow,
|
||||
@NotNull ReachingDefinitionsDfaInstance dfaInstance) {
|
||||
DefinitionMap result = new DefinitionMap();
|
||||
for (int i = 0; i < flow.length; i++) {
|
||||
Instruction insn = flow[i];
|
||||
if (insn instanceof ReadWriteVariableInstruction) {
|
||||
ReadWriteVariableInstruction rwInsn = (ReadWriteVariableInstruction) insn;
|
||||
ReadWriteVariableInstruction rwInsn = (ReadWriteVariableInstruction)insn;
|
||||
if (!rwInsn.isWrite()) {
|
||||
int idx = dfaInstance.getVarIndex(rwInsn.getVariableName());
|
||||
result.copyFrom(dfaResult.get(i), idx, i);
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
package org.jetbrains.plugins.groovy
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
|
||||
import org.jetbrains.annotations.NotNull
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GrControlFlowOwner
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement
|
||||
import org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs.FragmentVariableInfos
|
||||
import org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs.ReachingDefinitionsCollector
|
||||
import org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs.VariableInfo
|
||||
import org.jetbrains.plugins.groovy.util.TestUtils
|
||||
|
||||
/**
|
||||
* @auther ven
|
||||
*/
|
||||
public class ReachingDefsTest extends LightCodeInsightFixtureTestCase {
|
||||
|
||||
String basePath = TestUtils.testDataPath + 'groovy/reachingDefs/'
|
||||
|
||||
public void testAssign() { doTest() }
|
||||
public void testClosure() { doTest() }
|
||||
public void testClosure1() { doTest() }
|
||||
public void testEm1() { doTest() }
|
||||
public void testEm2() { doTest() }
|
||||
public void testEm3() { doTest() }
|
||||
public void testIf1() { doTest() }
|
||||
public void testInner() { doTest() }
|
||||
public void testLocal1() { doTest() }
|
||||
public void testLocal2() { doTest() }
|
||||
public void testSimpl1() { doTest() }
|
||||
public void testSimpl2() { doTest() }
|
||||
public void testSimpl3() { doTest() }
|
||||
public void testWhile1() { doTest() }
|
||||
|
||||
public void doTest() {
|
||||
final List<String> data = TestUtils.readInput(testDataPath + getTestName(true) + ".test")
|
||||
String text = data.get(0)
|
||||
|
||||
myFixture.configureByText(GroovyFileType.GROOVY_FILE_TYPE, text)
|
||||
|
||||
int selStart = myFixture.editor.selectionModel.selectionStart
|
||||
int selEnd = myFixture.editor.selectionModel.selectionEnd
|
||||
|
||||
final GroovyFile file = (GroovyFile)myFixture.file
|
||||
final PsiElement start = file.findElementAt(selStart)
|
||||
final PsiElement end = file.findElementAt(selEnd - 1)
|
||||
final GrControlFlowOwner owner = PsiTreeUtil.getParentOfType(PsiTreeUtil.findCommonParent(start, end), GrControlFlowOwner, false)
|
||||
assert owner != null
|
||||
GrStatement firstStatement = getStatement(start, owner)
|
||||
GrStatement lastStatement = getStatement(end, owner)
|
||||
final FragmentVariableInfos fragmentVariableInfos = ReachingDefinitionsCollector.obtainVariableFlowInformation(firstStatement, lastStatement)
|
||||
assertEquals(data.get(1), dumpInfo(fragmentVariableInfos).trim())
|
||||
}
|
||||
|
||||
private static String dumpInfo(FragmentVariableInfos fragmentVariableInfos) {
|
||||
StringBuilder builder = new StringBuilder()
|
||||
builder.append("input:\n")
|
||||
for (VariableInfo info : fragmentVariableInfos.inputVariableNames) {
|
||||
builder.append(info.name).append("\n")
|
||||
}
|
||||
|
||||
builder.append("output:\n")
|
||||
for (VariableInfo info : fragmentVariableInfos.outputVariableNames) {
|
||||
builder.append(info.name).append("\n")
|
||||
}
|
||||
|
||||
return builder.toString()
|
||||
}
|
||||
|
||||
private static GrStatement getStatement(@NotNull PsiElement element, PsiElement context) {
|
||||
while (element.parent != context) {
|
||||
element = element.parent
|
||||
assert element != null
|
||||
}
|
||||
|
||||
return (GrStatement) element
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
package org.jetbrains.plugins.groovy;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GrControlFlowOwner;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs.FragmentVariableInfos;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs.ReachingDefinitionsCollector;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs.VariableInfo;
|
||||
import org.jetbrains.plugins.groovy.util.TestUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @auther ven
|
||||
*/
|
||||
public class ReachingDefsTest extends LightCodeInsightFixtureTestCase {
|
||||
|
||||
@Override
|
||||
protected String getBasePath() {
|
||||
return TestUtils.getTestDataPath() + "groovy/reachingDefs/";
|
||||
}
|
||||
|
||||
public void testAssign() throws Throwable { doTest(); }
|
||||
public void testClosure() throws Throwable { doTest(); }
|
||||
public void testClosure1() throws Throwable { doTest(); }
|
||||
public void testEm1() throws Throwable { doTest(); }
|
||||
public void testEm2() throws Throwable { doTest(); }
|
||||
public void testEm3() throws Throwable { doTest(); }
|
||||
public void testIf1() throws Throwable { doTest(); }
|
||||
public void testInner() throws Throwable { doTest(); }
|
||||
public void testLocal1() throws Throwable { doTest(); }
|
||||
public void testLocal2() throws Throwable { doTest(); }
|
||||
public void testSimpl1() throws Throwable { doTest(); }
|
||||
public void testSimpl2() throws Throwable { doTest(); }
|
||||
public void testSimpl3() throws Throwable { doTest(); }
|
||||
public void testWhile1() throws Throwable { doTest(); }
|
||||
|
||||
public void doTest() throws Exception {
|
||||
final List<String> data = TestUtils.readInput(getTestDataPath() + getTestName(true) + ".test");
|
||||
String text = data.get(0);
|
||||
|
||||
myFixture.configureByText(GroovyFileType.GROOVY_FILE_TYPE, text);
|
||||
|
||||
int selStart = myFixture.getEditor().getSelectionModel().getSelectionStart();
|
||||
int selEnd = myFixture.getEditor().getSelectionModel().getSelectionEnd();
|
||||
|
||||
final GroovyFile file = (GroovyFile) myFixture.getFile();
|
||||
final PsiElement start = file.findElementAt(selStart);
|
||||
final PsiElement end = file.findElementAt(selEnd - 1);
|
||||
final GrControlFlowOwner owner = PsiTreeUtil.getParentOfType(PsiTreeUtil.findCommonParent(start, end), GrControlFlowOwner.class, false);
|
||||
assert owner != null;
|
||||
GrStatement firstStatement = getStatement(start, owner);
|
||||
GrStatement lastStatement = getStatement(end, owner);
|
||||
final FragmentVariableInfos fragmentVariableInfos = ReachingDefinitionsCollector.obtainVariableFlowInformation(firstStatement, lastStatement);
|
||||
assertEquals(data.get(1), dumpInfo(fragmentVariableInfos).trim());
|
||||
}
|
||||
|
||||
private static String dumpInfo(FragmentVariableInfos fragmentVariableInfos) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("input:\n");
|
||||
for (VariableInfo info : fragmentVariableInfos.getInputVariableNames()) {
|
||||
builder.append(info.getName()).append("\n");
|
||||
}
|
||||
|
||||
builder.append("output:\n");
|
||||
for (VariableInfo info : fragmentVariableInfos.getOutputVariableNames()) {
|
||||
builder.append(info.getName()).append("\n");
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private static GrStatement getStatement(@NotNull PsiElement element, PsiElement context) {
|
||||
while (element.getParent() != context) {
|
||||
element = element.getParent();
|
||||
assert element != null;
|
||||
}
|
||||
|
||||
return (GrStatement) element;
|
||||
}
|
||||
|
||||
}
|
||||
+5
-6
@@ -28,10 +28,7 @@ import org.jetbrains.plugins.groovy.util.TestUtils
|
||||
* @author ilyas
|
||||
*/
|
||||
public class ExtractMethodTest extends LightGroovyTestCase {
|
||||
@Override
|
||||
protected String getBasePath() {
|
||||
return TestUtils.testDataPath + "groovy/refactoring/extractMethod/";
|
||||
}
|
||||
final String basePath = TestUtils.testDataPath + 'groovy/refactoring/extractMethod/'
|
||||
|
||||
private void doAntiTest(String errorMessage) {
|
||||
GroovyExtractMethodHandler handler = configureFromText(readInput().get(0));
|
||||
@@ -94,7 +91,7 @@ public class ExtractMethodTest extends LightGroovyTestCase {
|
||||
public void testVen3() throws Throwable { doTest(); }
|
||||
public void testForIn() throws Throwable { doTest(); }
|
||||
public void testInCatch() {doTest();}
|
||||
|
||||
|
||||
public void testClosureIt() throws Throwable { doTest(); }
|
||||
public void testImplicitReturn() {doTest();}
|
||||
|
||||
@@ -109,7 +106,7 @@ public class ExtractMethodTest extends LightGroovyTestCase {
|
||||
public void testLastBlockStatementInterruptsControlFlow() {doTest();}
|
||||
|
||||
public void testAOOBE() {doTest();}
|
||||
|
||||
|
||||
public void testWildCardReturnType() {doTest();}
|
||||
public void testParamChangedInsideExtractedMethod() {doTest();}
|
||||
|
||||
@@ -117,4 +114,6 @@ public class ExtractMethodTest extends LightGroovyTestCase {
|
||||
|
||||
public void testArgsUsedOnlyInClosure() {doTest()}
|
||||
public void testArgsUsedOnlyInAnonymousClass() {doTest()}
|
||||
|
||||
public void testTwoVars() {doTest()}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
def foo() {
|
||||
<begin>int i = 0
|
||||
int j = 1
|
||||
while (condition) {
|
||||
i = i + 1
|
||||
j = i
|
||||
}<end>
|
||||
return j
|
||||
}
|
||||
-----
|
||||
def foo() {
|
||||
int j = testMethod()
|
||||
return j
|
||||
}
|
||||
|
||||
private int testMethod() {
|
||||
int i = 0
|
||||
int j = 1
|
||||
while (condition) {
|
||||
i = i + 1
|
||||
j = i
|
||||
}
|
||||
return j
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
protected static def getGeneratedFileNames() {
|
||||
def foo = 0
|
||||
while (true) {
|
||||
while (cond) {
|
||||
<begin> println(foo)
|
||||
foo = ""
|
||||
<end> }
|
||||
@@ -10,7 +10,7 @@ protected static def getGeneratedFileNames() {
|
||||
-----
|
||||
protected static def getGeneratedFileNames() {
|
||||
def foo = 0
|
||||
while (true) {
|
||||
while (cond) {
|
||||
foo = <caret>testMethod(foo)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
protected static def getGeneratedFileNames() {
|
||||
foo = 0
|
||||
while (true) {
|
||||
while (cond) {
|
||||
<begin> println(foo)
|
||||
foo = ""
|
||||
<end> }
|
||||
@@ -10,7 +10,7 @@ protected static def getGeneratedFileNames() {
|
||||
-----
|
||||
protected static def getGeneratedFileNames() {
|
||||
foo = 0
|
||||
while (true) {
|
||||
while (cond) {
|
||||
foo = <caret>testMethod(foo)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
protected static def getGeneratedFileNames() {
|
||||
foo = 0
|
||||
def foo = 0
|
||||
while (true) {
|
||||
<begin> println(foo)
|
||||
foo = ""
|
||||
<end> }
|
||||
|
||||
int t = foo
|
||||
}
|
||||
-----
|
||||
protected static def getGeneratedFileNames() {
|
||||
foo = 0
|
||||
def foo = 0
|
||||
while (true) {
|
||||
foo = <caret>testMethod(foo)
|
||||
}
|
||||
|
||||
int t = foo
|
||||
}
|
||||
|
||||
private static String testMethod(Serializable foo) {
|
||||
|
||||
@@ -20,12 +20,15 @@ import com.intellij.compiler.CompilerConfiguration;
|
||||
import com.intellij.execution.configurations.ConfigurationUtil;
|
||||
import com.intellij.execution.testframework.SourceScope;
|
||||
import com.intellij.ide.util.ClassFilter;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.util.PsiUtilBase;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -49,10 +52,14 @@ public class TestClassFilter implements ClassFilter.ClassFilterWithScope {
|
||||
public Project getProject() { return myProject; }
|
||||
|
||||
public boolean isAccepted(final PsiClass aClass) {
|
||||
return ConfigurationUtil.PUBLIC_INSTANTIATABLE_CLASS.value(aClass) &&
|
||||
(aClass.isInheritor(myBase, true) || JUnitUtil.isTestClass(aClass))
|
||||
&& !CompilerConfiguration.getInstance(getProject()).isExcludedFromCompilation(PsiUtilBase.getVirtualFile(aClass))
|
||||
;
|
||||
return ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
|
||||
@Override
|
||||
public Boolean compute() {
|
||||
return ConfigurationUtil.PUBLIC_INSTANTIATABLE_CLASS.value(aClass) &&
|
||||
(aClass.isInheritor(myBase, true) || JUnitUtil.isTestClass(aClass))
|
||||
&& !CompilerConfiguration.getInstance(getProject()).isExcludedFromCompilation(PsiUtilCore.getVirtualFile(aClass));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public TestClassFilter intersectionWith(final GlobalSearchScope scope) {
|
||||
@@ -78,9 +85,14 @@ public class TestClassFilter implements ClassFilter.ClassFilterWithScope {
|
||||
}
|
||||
return new TestClassFilter(testCase, sourceScope.getGlobalSearchScope()){
|
||||
@Override
|
||||
public boolean isAccepted(PsiClass aClass) {
|
||||
public boolean isAccepted(final PsiClass aClass) {
|
||||
if (super.isAccepted(aClass)) {
|
||||
final String qualifiedName = aClass.getQualifiedName();
|
||||
final String qualifiedName = ApplicationManager.getApplication().runReadAction(new Computable<String>() {
|
||||
@Override
|
||||
public String compute() {
|
||||
return aClass.getQualifiedName();
|
||||
}
|
||||
});
|
||||
for (Pattern compilePattern : compilePatterns) {
|
||||
if (compilePattern.matcher(qualifiedName).matches()) {
|
||||
return true;
|
||||
|
||||
@@ -146,6 +146,7 @@ http
|
||||
https
|
||||
impl
|
||||
inbox
|
||||
incrementer
|
||||
indextype
|
||||
indices
|
||||
infile
|
||||
|
||||
@@ -18,7 +18,9 @@ package com.theoryinpractice.testng.model;
|
||||
import com.intellij.codeInsight.AnnotationUtil;
|
||||
import com.intellij.execution.configurations.ConfigurationUtil;
|
||||
import com.intellij.ide.util.ClassFilter;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
@@ -60,35 +62,40 @@ public class TestClassFilter implements ClassFilter.ClassFilterWithScope
|
||||
return new TestClassFilter(this.scope.intersectWith(scope), project, includeConfig, checkClassCanBeInstantiated);
|
||||
}
|
||||
|
||||
public boolean isAccepted(PsiClass psiClass) {
|
||||
if(!ConfigurationUtil.PUBLIC_INSTANTIATABLE_CLASS.value(psiClass)) return false;
|
||||
//PsiManager manager = PsiManager.getInstance(project);
|
||||
//if(manager.getEffectiveLanguageLevel().compareTo(LanguageLevel.JDK_1_5) < 0) return true;
|
||||
boolean hasTest = TestNGUtil.hasTest(psiClass);
|
||||
if (hasTest) {
|
||||
if (checkClassCanBeInstantiated) {
|
||||
final PsiMethod[] constructors = psiClass.getConstructors();
|
||||
if (constructors.length > 0) {
|
||||
boolean canBeInstantiated = false;
|
||||
for (PsiMethod constructor : constructors) {
|
||||
if (constructor.getParameterList().getParametersCount() == 0) {
|
||||
canBeInstantiated = true;
|
||||
break;
|
||||
}
|
||||
if (AnnotationUtil.isAnnotated(constructor, Arrays.asList(GUICE_INJECTION, FACTORY_INJECTION), true)) {
|
||||
canBeInstantiated = true;
|
||||
break;
|
||||
public boolean isAccepted(final PsiClass psiClass) {
|
||||
return ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
|
||||
@Override
|
||||
public Boolean compute() {
|
||||
if(!ConfigurationUtil.PUBLIC_INSTANTIATABLE_CLASS.value(psiClass)) return false;
|
||||
//PsiManager manager = PsiManager.getInstance(project);
|
||||
//if(manager.getEffectiveLanguageLevel().compareTo(LanguageLevel.JDK_1_5) < 0) return true;
|
||||
boolean hasTest = TestNGUtil.hasTest(psiClass);
|
||||
if (hasTest) {
|
||||
if (checkClassCanBeInstantiated) {
|
||||
final PsiMethod[] constructors = psiClass.getConstructors();
|
||||
if (constructors.length > 0) {
|
||||
boolean canBeInstantiated = false;
|
||||
for (PsiMethod constructor : constructors) {
|
||||
if (constructor.getParameterList().getParametersCount() == 0) {
|
||||
canBeInstantiated = true;
|
||||
break;
|
||||
}
|
||||
if (AnnotationUtil.isAnnotated(constructor, Arrays.asList(GUICE_INJECTION, FACTORY_INJECTION), true)) {
|
||||
canBeInstantiated = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!canBeInstantiated){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!canBeInstantiated){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return includeConfig && TestNGUtil.hasConfig(psiClass);
|
||||
return includeConfig && TestNGUtil.hasConfig(psiClass);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public Project getProject() {
|
||||
|
||||
@@ -17,7 +17,9 @@ package com.theoryinpractice.testng.model;
|
||||
|
||||
import com.intellij.execution.configurations.ConfigurationUtil;
|
||||
import com.intellij.ide.util.ClassFilter;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.theoryinpractice.testng.util.TestNGUtil;
|
||||
@@ -35,10 +37,15 @@ public class TestListenerFilter implements ClassFilter.ClassFilterWithScope
|
||||
this.project = project;
|
||||
}
|
||||
|
||||
public boolean isAccepted(PsiClass psiClass) {
|
||||
if (!ConfigurationUtil.PUBLIC_INSTANTIATABLE_CLASS.value(psiClass)) return false;
|
||||
public boolean isAccepted(final PsiClass psiClass) {
|
||||
return ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
|
||||
@Override
|
||||
public Boolean compute() {
|
||||
if (!ConfigurationUtil.PUBLIC_INSTANTIATABLE_CLASS.value(psiClass)) return false;
|
||||
|
||||
return TestNGUtil.inheritsITestListener(psiClass);
|
||||
return TestNGUtil.inheritsITestListener(psiClass);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public Project getProject() {
|
||||
|
||||
@@ -19,7 +19,7 @@ import com.intellij.icons.AllIcons;
|
||||
import com.intellij.ide.BrowserUtil;
|
||||
import com.intellij.ide.browsers.chrome.ChromeSettings;
|
||||
import com.intellij.ide.browsers.firefox.FirefoxSettings;
|
||||
import com.intellij.ide.browsers.impl.UrlOpenerImpl;
|
||||
import com.intellij.ide.browsers.impl.DefaultUrlOpener;
|
||||
import com.intellij.openapi.components.*;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Conditions;
|
||||
@@ -217,7 +217,7 @@ public class BrowsersConfiguration implements PersistentStateComponent<Element>
|
||||
@Nullable final String url,
|
||||
final boolean forceOpenNewInstanceOnMac,
|
||||
String... parameters) {
|
||||
UrlOpenerImpl.doLaunchBrowser(family, url, parameters, Conditions.<String>alwaysTrue(), forceOpenNewInstanceOnMac);
|
||||
DefaultUrlOpener.doLaunchBrowser(family, url, parameters, Conditions.<String>alwaysTrue(), forceOpenNewInstanceOnMac);
|
||||
}
|
||||
|
||||
public static void launchBrowser(final @NotNull BrowserFamily family,
|
||||
@@ -225,7 +225,7 @@ public class BrowsersConfiguration implements PersistentStateComponent<Element>
|
||||
final boolean forceOpenNewInstanceOnMac,
|
||||
final Condition<String> browserSpecificParametersFilter,
|
||||
String... parameters) {
|
||||
UrlOpenerImpl.doLaunchBrowser(family, url, parameters, browserSpecificParametersFilter, forceOpenNewInstanceOnMac);
|
||||
DefaultUrlOpener.doLaunchBrowser(family, url, parameters, browserSpecificParametersFilter, forceOpenNewInstanceOnMac);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
+2
-2
@@ -38,8 +38,8 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class UrlOpenerImpl extends UrlOpener {
|
||||
private static final Logger LOG = Logger.getInstance(UrlOpenerImpl.class);
|
||||
public class DefaultUrlOpener extends UrlOpener {
|
||||
private static final Logger LOG = Logger.getInstance(DefaultUrlOpener.class);
|
||||
|
||||
@Override
|
||||
public boolean openUrl(BrowsersConfiguration.BrowserFamily family, String url) {
|
||||
Reference in New Issue
Block a user