diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/MarkObjectAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/MarkObjectAction.java index f7c328d21e8d..37b129cd385f 100644 --- a/java/debugger/impl/src/com/intellij/debugger/actions/MarkObjectAction.java +++ b/java/debugger/impl/src/com/intellij/debugger/actions/MarkObjectAction.java @@ -15,6 +15,7 @@ */ package com.intellij.debugger.actions; +import com.intellij.codeInsight.daemon.impl.HighlightInfoType; import com.intellij.debugger.engine.DebugProcessImpl; import com.intellij.debugger.engine.DebuggerUtils; import com.intellij.debugger.engine.events.DebuggerContextCommandImpl; @@ -25,19 +26,23 @@ import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl; import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl; import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl; import com.intellij.debugger.ui.tree.ValueDescriptor; -import com.intellij.debugger.ui.tree.ValueMarkup; +import com.intellij.xdebugger.impl.ui.tree.ValueMarkup; import com.intellij.idea.ActionsBundle; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.colors.EditorColorsManager; +import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Ref; import com.intellij.util.containers.HashMap; import com.sun.jdi.*; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.Collections; import java.util.List; import java.util.Map; @@ -48,6 +53,7 @@ import java.util.Map; */ public class MarkObjectAction extends DebuggerAction { private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.actions.MarkObjectAction"); + public static final long AUTO_MARKUP_REFERRING_OBJECTS_LIMIT = 100L; // todo: some reasonable limit private final String MARK_TEXT = ActionsBundle.message("action.Debugger.MarkObject.text"); private final String UNMARK_TEXT = ActionsBundle.message("action.Debugger.MarkObject.unmark.text"); @@ -79,13 +85,17 @@ public class MarkObjectAction extends DebuggerAction { valueDescriptor.setMarkup(debugProcess, null); } else { - final ValueMarkup suggestedMarkup = new ValueMarkup(valueDescriptor.getName(), Color.RED); + final String defaultText = valueDescriptor.getName(); final Ref> result = new Ref>(null); try { final boolean suggestAdditionalMarkup = canSuggestAdditionalMarkup(debugProcess, valueDescriptor.getValue()); SwingUtilities.invokeAndWait(new Runnable() { public void run() { - result.set(ObjectMarkupPropertiesDialog.chooseMarkup(suggestedMarkup, suggestAdditionalMarkup)); + ObjectMarkupPropertiesDialog dialog = new ObjectMarkupPropertiesDialog(defaultText, suggestAdditionalMarkup); + dialog.show(); + if (dialog.isOK()) { + result.set(Pair.create(dialog.getConfiguredMarkup(), dialog.isMarkAdditionalFields())); + } } }); } @@ -176,7 +186,7 @@ public class MarkObjectAction extends DebuggerAction { final ValueMarkup markup = result.get((ObjectReference)fieldValue); final String fieldName = field.name(); - final Color autoMarkupColor = ValueMarkup.getAutoMarkupColor(); + final Color autoMarkupColor = getAutoMarkupColor(); if (markup == null) { result.put((ObjectReference)fieldValue, new ValueMarkup(fieldName, autoMarkupColor, createMarkupTooltipText(null, refType, fieldName))); } @@ -197,8 +207,9 @@ public class MarkObjectAction extends DebuggerAction { // invoke the following method using Reflection in order to remain compilable on jdk 1.5 // java.util.List referringObjects(long l); try { - final java.lang.reflect.Method apiMethod = ObjectReference.class.getMethod("referringObjects", long.class); - return (List)apiMethod.invoke(value, ValueMarkup.AUTO_MARKUP_REFERRING_OBJECTS_LIMIT); + final Method apiMethod = ObjectReference.class.getMethod("referringObjects", long.class); + //noinspection unchecked + return (List)apiMethod.invoke(value, AUTO_MARKUP_REFERRING_OBJECTS_LIMIT); } catch (IllegalAccessException e) { LOG.error(e); // should not happen @@ -211,7 +222,7 @@ public class MarkObjectAction extends DebuggerAction { return Collections.emptyList(); } - private static String createMarkupTooltipText(String prefix, ReferenceType refType, String fieldName) { + private static String createMarkupTooltipText(@Nullable String prefix, ReferenceType refType, String fieldName) { final StringBuilder builder = new StringBuilder(); if (prefix == null) { builder.append("Value referenced from:"); @@ -241,4 +252,10 @@ public class MarkObjectAction extends DebuggerAction { presentation.setVisible(enable); presentation.setText(text); } + + public static Color getAutoMarkupColor() { + final EditorColorsManager manager = EditorColorsManager.getInstance(); + final TextAttributes textAttributes = manager.getGlobalScheme().getAttributes(HighlightInfoType.STATIC_FIELD.getAttributesKey()); + return textAttributes.getForegroundColor(); + } } diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/ObjectMarkupPropertiesDialog.form b/java/debugger/impl/src/com/intellij/debugger/actions/ObjectMarkupPropertiesDialog.form new file mode 100644 index 000000000000..a0b7a67cbe5e --- /dev/null +++ b/java/debugger/impl/src/com/intellij/debugger/actions/ObjectMarkupPropertiesDialog.form @@ -0,0 +1,29 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/ObjectMarkupPropertiesDialog.java b/java/debugger/impl/src/com/intellij/debugger/actions/ObjectMarkupPropertiesDialog.java index 7182194109ca..15ef421bdea1 100644 --- a/java/debugger/impl/src/com/intellij/debugger/actions/ObjectMarkupPropertiesDialog.java +++ b/java/debugger/impl/src/com/intellij/debugger/actions/ObjectMarkupPropertiesDialog.java @@ -15,140 +15,56 @@ */ package com.intellij.debugger.actions; -import com.intellij.debugger.ui.tree.ValueMarkup; -import com.intellij.openapi.ui.DialogWrapper; -import com.intellij.openapi.ui.FixedSizeButton; +import com.intellij.ide.util.PropertiesComponent; import com.intellij.openapi.ui.ex.MultiLineLabel; -import com.intellij.openapi.util.Pair; -import com.intellij.ui.ColorChooser; -import com.intellij.ui.DocumentAdapter; -import com.intellij.ui.SimpleColoredComponent; -import com.intellij.ui.SimpleTextAttributes; -import com.intellij.util.Alarm; +import com.intellij.xdebugger.impl.ui.tree.ValueMarkerPresentationDialog; +import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import javax.swing.*; -import javax.swing.event.DocumentEvent; import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; /** * @author Eugene Zhuravlev * Date: Feb 4, 2007 */ -public class ObjectMarkupPropertiesDialog extends DialogWrapper { - private final JTextField myTextMarkupField; - private final JCheckBox myCbMarkAdditionalFields; - private final SimpleColoredComponent myColorSample; - private SimpleTextAttributes myAttributes; - private final Alarm myUpdateAlarm; - private static final int UPDATE_DELAY = 200; - private static Boolean ourMarkCbSavedState; +public class ObjectMarkupPropertiesDialog extends ValueMarkerPresentationDialog { + @NonNls private static final String MARK_ALL_REFERENCED_VALUES_KEY = "debugger.mark.all.referenced.values"; + private JCheckBox myCbMarkAdditionalFields; private final boolean mySuggestAdditionalMarkup; + private JPanel myAdditionalPropertiesPanel; + private MultiLineLabel myDescriptionLabel; - public ObjectMarkupPropertiesDialog(@NotNull final ValueMarkup suggestion, boolean suggestAdditionalMarkup) { - super(true); + public ObjectMarkupPropertiesDialog(@NotNull final String defaultText, boolean suggestAdditionalMarkup) { + super(defaultText); mySuggestAdditionalMarkup = suggestAdditionalMarkup; - setTitle("Select object label"); - setModal(true); - myTextMarkupField = new JTextField(30); - myCbMarkAdditionalFields = new JCheckBox("Mark values referenced from constant fields", ourMarkCbSavedState == null? suggestAdditionalMarkup : ourMarkCbSavedState); - myCbMarkAdditionalFields.addItemListener(new ItemListener() { - public void itemStateChanged(ItemEvent e) { - ourMarkCbSavedState = myCbMarkAdditionalFields.isSelected(); - } - }); - myColorSample = new SimpleColoredComponent(); - myUpdateAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD); - myAttributes = createAttributes(suggestion.getColor()); - SwingUtilities.invokeLater(new Runnable() { - public void run() { - myTextMarkupField.setText(suggestion.getText().trim()); - updateLabelSample(0); - } - }); + myDescriptionLabel.setText("If the value is referenced by a constant field of an abstract class,\n" + + "IDEA could additionally mark all values referenced from this class with the names of referencing fields."); + myCbMarkAdditionalFields.setSelected(PropertiesComponent.getInstance().getBoolean(MARK_ALL_REFERENCED_VALUES_KEY, true)); init(); } - - public JComponent getPreferredFocusedComponent() { - return myTextMarkupField; - } - - protected void dispose() { - myUpdateAlarm.dispose(); - super.dispose(); - } - - @Nullable - protected JComponent createCenterPanel() { - final JPanel mainPanel = new JPanel(new GridBagLayout()); - mainPanel.add(new JLabel("Label:"), new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0)); - mainPanel.add(myTextMarkupField, new GridBagConstraints(1, GridBagConstraints.RELATIVE, 2, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0)); - - final JPanel samplePanel = new JPanel(new BorderLayout()); - samplePanel.add(myColorSample, BorderLayout.CENTER); - samplePanel.setBorder(BorderFactory.createEtchedBorder()); - final FixedSizeButton chooseColorButton = new FixedSizeButton(samplePanel); - - double weighty = mySuggestAdditionalMarkup ? 0.0 : 1.0; - mainPanel.add(new JLabel("Preview: "), new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 0.0, weighty, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 0, 0, 0), 0, 0)); - mainPanel.add(samplePanel, new GridBagConstraints(1, GridBagConstraints.RELATIVE, 1, 1, 1.0, weighty, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(5, 0, 0, 0), 0, 0)); - mainPanel.add(chooseColorButton, new GridBagConstraints(2, GridBagConstraints.RELATIVE, 1, 1, 0.0, weighty, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(5, 0, 0, 0), 0, 0)); - + @Override + protected void doOKAction() { if (mySuggestAdditionalMarkup) { - final JPanel panel = new JPanel(new BorderLayout()); - panel.add(new MultiLineLabel( - "If the value is referenced by a constant field of an abstract class,\nIDEA could additionally mark all values referenced from this class with the names of referencing fields." - ), BorderLayout.CENTER); - panel.add(myCbMarkAdditionalFields, BorderLayout.SOUTH); - myCbMarkAdditionalFields.setMnemonic('M'); - - mainPanel.add(panel, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 3, 1, 0.0, 1.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(10, 0, 0, 0), 0, 0)); + PropertiesComponent.getInstance().setValue(MARK_ALL_REFERENCED_VALUES_KEY, Boolean.toString(myCbMarkAdditionalFields.isSelected())); } - - myTextMarkupField.getDocument().addDocumentListener(new DocumentAdapter() { - protected void textChanged(final DocumentEvent e) { - updateLabelSample(UPDATE_DELAY); - } - }); - chooseColorButton.addActionListener(new ActionListener() { - public void actionPerformed(final ActionEvent e) { - final Color color = ColorChooser.chooseColor(myColorSample, "Choose label color", null); - myAttributes = createAttributes(color); - updateLabelSample(UPDATE_DELAY); - } - }); - return mainPanel; + super.doOKAction(); } - private void updateLabelSample(final int updateDelay) { - myUpdateAlarm.cancelAllRequests(); - myUpdateAlarm.addRequest(new Runnable() { - public void run() { - myColorSample.clear(); - myColorSample.append(myTextMarkupField.getText().trim(), myAttributes); - myColorSample.repaint(); - } - }, updateDelay); - } - - public static Pair chooseMarkup(ValueMarkup suggestion, boolean suggestAdditionalMarkup) { - final ObjectMarkupPropertiesDialog dialog = new ObjectMarkupPropertiesDialog(suggestion, suggestAdditionalMarkup); - dialog.show(); - if (dialog.isOK()) { - final String text = dialog.myTextMarkupField.getText().trim(); - final Color color = dialog.myAttributes.getFgColor(); - return text.length() > 0? new Pair(new ValueMarkup(text, color, suggestion.getToolTipText()), dialog.myCbMarkAdditionalFields.isSelected()) : null; + @Override + protected JComponent createCenterPanel() { + JComponent mainPanel = super.createCenterPanel(); + if (!mySuggestAdditionalMarkup) { + return mainPanel; } - return null; + JPanel panel = new JPanel(new BorderLayout()); + panel.add(BorderLayout.CENTER, mainPanel); + panel.add(BorderLayout.SOUTH, myAdditionalPropertiesPanel); + return panel; } - private static SimpleTextAttributes createAttributes(final Color color) { - return new SimpleTextAttributes(SimpleTextAttributes.STYLE_BOLD, color); + public boolean isMarkAdditionalFields() { + return myCbMarkAdditionalFields.isSelected(); } } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/CodeFragmentFactoryContextWrapper.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/CodeFragmentFactoryContextWrapper.java index cda720cb0897..8c2a1de39bc4 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/CodeFragmentFactoryContextWrapper.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/CodeFragmentFactoryContextWrapper.java @@ -18,7 +18,7 @@ package com.intellij.debugger.engine.evaluation; import com.intellij.debugger.DebuggerManagerEx; import com.intellij.debugger.engine.DebugProcessImpl; import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl; -import com.intellij.debugger.ui.tree.ValueMarkup; +import com.intellij.xdebugger.impl.ui.tree.ValueMarkup; import com.intellij.openapi.fileTypes.LanguageFileType; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Key; diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerSessionTab.java b/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerSessionTab.java index a95baf60fdf6..a024d125154f 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerSessionTab.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerSessionTab.java @@ -94,7 +94,6 @@ public class DebuggerSessionTab extends DebuggerSessionTabBase implements Dispos private ExecutionEnvironment myEnvironment; private RunProfile myConfiguration; - public static final String BREAKPOINT_CONDITION = "breakpoint"; private final ThreadsPanel myThreadsPanel; private static final String THREAD_DUMP_CONTENT_PREFIX = "Dump"; private final Icon myIcon; @@ -104,10 +103,10 @@ public class DebuggerSessionTab extends DebuggerSessionTabBase implements Dispos myIcon = icon; - myUi = RunnerLayoutUi.Factory.getInstance(project).create("JavaDebugger", DebuggerBundle.message("title.generic.debug.dialog"), sessionName, this); + myUi = RunnerLayoutUi.Factory.getInstance(project).create("JavaDebugger", XDebuggerBundle.message("xdebugger.default.content.title"), sessionName, this); - myUi.getDefaults().initTabDefaults(0, "Debugger", null). - initFocusContent(DebuggerContentInfo.FRAME_CONTENT, BREAKPOINT_CONDITION). + myUi.getDefaults().initTabDefaults(0, XDebuggerBundle.message("xdebugger.debugger.tab.title"), null). + initFocusContent(DebuggerContentInfo.FRAME_CONTENT, XDebuggerUIConstants.LAYOUT_VIEW_BREAKPOINT_CONDITION). initFocusContent(DebuggerContentInfo.CONSOLE_CONTENT, LayoutViewOptions.STARTUP, new LayoutAttractionPolicy.FocusOnce(false)); final DefaultActionGroup focus = new DefaultActionGroup(); @@ -479,9 +478,9 @@ public class DebuggerSessionTab extends DebuggerSessionTabBase implements Dispos private void attractFramesOnPause(final int event) { if (DebuggerSession.EVENT_PAUSE == event) { - myUi.attractBy(BREAKPOINT_CONDITION); + myUi.attractBy(XDebuggerUIConstants.LAYOUT_VIEW_BREAKPOINT_CONDITION); } else if (DebuggerSession.EVENT_RESUME == event) { - myUi.clearAttractionBy(BREAKPOINT_CONDITION); + myUi.clearAttractionBy(XDebuggerUIConstants.LAYOUT_VIEW_BREAKPOINT_CONDITION); } } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerStatementEditor.java b/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerStatementEditor.java index b3a24995596d..5d16074e0706 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerStatementEditor.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerStatementEditor.java @@ -61,6 +61,7 @@ public class DebuggerStatementEditor extends DebuggerEditorImpl { return false; } }; + myEditor.setCenterByHeight(false); setLayout(new BorderLayout()); add(myEditor, BorderLayout.CENTER); diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointWithHighlighter.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointWithHighlighter.java index 4f0f3d15c370..e8dff17807f2 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointWithHighlighter.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointWithHighlighter.java @@ -654,7 +654,7 @@ public abstract class BreakpointWithHighlighter extends Breakpoint { return new AnAction() { public void actionPerformed(AnActionEvent e) { ENABLED = !ENABLED; - DebuggerManagerEx.getInstanceEx(getProject()).getBreakpointManager().fireBreakpointChanged(BreakpointWithHighlighter.this); + DebuggerManagerEx.getInstanceEx(BreakpointWithHighlighter.this.getProject()).getBreakpointManager().fireBreakpointChanged(BreakpointWithHighlighter.this); updateUI(); } }; diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/actions/FocusOnBreakpointAction.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/actions/FocusOnBreakpointAction.java index 74c2b60220ed..91b223c613c9 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/actions/FocusOnBreakpointAction.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/actions/FocusOnBreakpointAction.java @@ -16,10 +16,10 @@ package com.intellij.debugger.ui.breakpoints.actions; import com.intellij.execution.ui.actions.AbstractFocusOnAction; -import com.intellij.debugger.ui.DebuggerSessionTab; +import com.intellij.xdebugger.impl.ui.XDebuggerUIConstants; public class FocusOnBreakpointAction extends AbstractFocusOnAction { public FocusOnBreakpointAction() { - super(DebuggerSessionTab.BREAKPOINT_CONDITION); + super(XDebuggerUIConstants.LAYOUT_VIEW_BREAKPOINT_CONDITION); } } \ No newline at end of file diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/DebuggerTreeBase.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/DebuggerTreeBase.java index 5c8578e6bbf3..c5f730109d16 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/DebuggerTreeBase.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/DebuggerTreeBase.java @@ -345,43 +345,37 @@ public class DebuggerTreeBase extends DnDAwareTree implements Disposable { if (tabSize < 0) { tabSize = 0; } - final StringBuffer buf = new StringBuffer(); - try { - boolean special = false; - for (int idx = 0; idx < text.length(); idx++) { - char c = text.charAt(idx); - if (special) { - if (c == 't') { // convert tabs to spaces - for (int i = 0; i < tabSize; i++) { - buf.append(' '); - } + final StringBuilder buf = new StringBuilder(); + boolean special = false; + for (int idx = 0; idx < text.length(); idx++) { + char c = text.charAt(idx); + if (special) { + if (c == 't') { // convert tabs to spaces + for (int i = 0; i < tabSize; i++) { + buf.append(' '); } - else if (c == 'r') { // remove occurrences of '\r' - } - else if (c == 'n') { - buf.append('\n'); - } - else { - buf.append('\\'); - buf.append(c); - } - special = false; + } + else if (c == 'r') { // remove occurrences of '\r' + } + else if (c == 'n') { + buf.append('\n'); } else { - if (c == '\\') { - special = true; - } - else { - buf.append(c); - } + buf.append('\\'); + buf.append(c); + } + special = false; + } + else { + if (c == '\\') { + special = true; + } + else { + buf.append(c); } } - - return buf.toString(); - } - finally { - } + return buf.toString(); } public void dispose() { diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/DebuggerTreeRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/DebuggerTreeRenderer.java index 47987f3086a4..9cc837b5f151 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/DebuggerTreeRenderer.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/DebuggerTreeRenderer.java @@ -20,7 +20,7 @@ import com.intellij.debugger.impl.DebuggerContextImpl; import com.intellij.debugger.impl.DebuggerUtilsEx; import com.intellij.debugger.ui.impl.watch.*; import com.intellij.debugger.ui.tree.ValueDescriptor; -import com.intellij.debugger.ui.tree.ValueMarkup; +import com.intellij.xdebugger.impl.ui.tree.ValueMarkup; import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.ColoredTreeCellRenderer; diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/FramesListRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/FramesListRenderer.java index b28f350e2c2e..ccacf43c595b 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/FramesListRenderer.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/FramesListRenderer.java @@ -16,7 +16,7 @@ package com.intellij.debugger.ui.impl; import com.intellij.debugger.ui.impl.watch.StackFrameDescriptorImpl; -import com.intellij.debugger.ui.tree.ValueMarkup; +import com.intellij.xdebugger.impl.ui.tree.ValueMarkup; import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.editor.colors.EditorColorsScheme; import com.intellij.openapi.util.Comparing; diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/DebuggerTreeNodeImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/DebuggerTreeNodeImpl.java index 02ba340ba5e1..665a6a1ad25d 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/DebuggerTreeNodeImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/DebuggerTreeNodeImpl.java @@ -29,7 +29,7 @@ import com.intellij.debugger.ui.impl.tree.TreeBuilderNode; import com.intellij.debugger.ui.tree.DebuggerTreeNode; import com.intellij.debugger.ui.tree.NodeDescriptor; import com.intellij.debugger.ui.tree.ValueDescriptor; -import com.intellij.debugger.ui.tree.ValueMarkup; +import com.intellij.xdebugger.impl.ui.tree.ValueMarkup; import com.intellij.debugger.ui.tree.render.DescriptorLabelListener; import com.intellij.debugger.ui.tree.render.NodeRenderer; import com.intellij.openapi.application.ApplicationManager; diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/NodeDescriptorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/NodeDescriptorImpl.java index 92228696b128..fc9c87ad6208 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/NodeDescriptorImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/NodeDescriptorImpl.java @@ -21,7 +21,7 @@ import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil; import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; import com.intellij.debugger.ui.tree.NodeDescriptor; -import com.intellij.debugger.ui.tree.ValueMarkup; +import com.intellij.xdebugger.impl.ui.tree.ValueMarkup; import com.intellij.debugger.ui.tree.render.DescriptorLabelListener; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Key; diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/StackFrameDescriptorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/StackFrameDescriptorImpl.java index 93a257cef10e..5ed274b7aa35 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/StackFrameDescriptorImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/StackFrameDescriptorImpl.java @@ -25,7 +25,7 @@ import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; import com.intellij.debugger.jdi.StackFrameProxyImpl; import com.intellij.debugger.settings.ThreadsViewSettings; import com.intellij.debugger.ui.tree.StackFrameDescriptor; -import com.intellij.debugger.ui.tree.ValueMarkup; +import com.intellij.xdebugger.impl.ui.tree.ValueMarkup; import com.intellij.debugger.ui.tree.render.DescriptorLabelListener; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.roots.ProjectFileIndex; diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ValueDescriptorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ValueDescriptorImpl.java index 8039f7083821..0895b5447e0f 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ValueDescriptorImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ValueDescriptorImpl.java @@ -29,7 +29,7 @@ import com.intellij.debugger.jdi.VirtualMachineProxyImpl; import com.intellij.debugger.settings.NodeRendererSettings; import com.intellij.debugger.ui.tree.NodeDescriptor; import com.intellij.debugger.ui.tree.ValueDescriptor; -import com.intellij.debugger.ui.tree.ValueMarkup; +import com.intellij.xdebugger.impl.ui.tree.ValueMarkup; import com.intellij.debugger.ui.tree.render.ClassRenderer; import com.intellij.debugger.ui.tree.render.DescriptorLabelListener; import com.intellij.debugger.ui.tree.render.NodeRenderer; diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/ValueDescriptor.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/ValueDescriptor.java index 9c30a24ba63d..284334301e23 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/tree/ValueDescriptor.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/ValueDescriptor.java @@ -19,6 +19,7 @@ import com.intellij.debugger.DebuggerContext; import com.intellij.debugger.engine.DebugProcess; import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.psi.PsiExpression; +import com.intellij.xdebugger.impl.ui.tree.ValueMarkup; import com.sun.jdi.Value; import org.jetbrains.annotations.Nullable; diff --git a/java/execution/impl/src/com/intellij/execution/filters/AuxiliaryCallsFolding.java b/java/execution/impl/src/com/intellij/execution/filters/AuxiliaryCallsFolding.java deleted file mode 100644 index 83df6698588d..000000000000 --- a/java/execution/impl/src/com/intellij/execution/filters/AuxiliaryCallsFolding.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.intellij.execution.filters; - -import com.intellij.execution.ConsoleFolding; -import com.intellij.openapi.util.TextRange; -import com.intellij.openapi.util.Trinity; - -import java.util.List; - -/** - * @author peter - */ -public class AuxiliaryCallsFolding extends ConsoleFolding { - @Override - public boolean shouldFoldLine(String line) { - final Trinity pair = ExceptionFilter.parseExceptionLine(line); - return pair != null && shouldFold(pair.first, pair.second); - } - - private static boolean shouldFold(String className, String methodName) { - for (StackFrameFilter provider : StackFrameFilter.EP_NAME.getExtensions()) { - if (provider.isAuxiliaryFrame(className, methodName)) { - return true; - } - } - return false; - } - - - @Override - public String getPlaceholderText(List lines) { - return " <" + lines.size() + " internal calls>"; - } -} diff --git a/java/execution/openapi/src/com/intellij/execution/filters/ReflectionStackFrameFilter.java b/java/execution/openapi/src/com/intellij/execution/filters/ReflectionStackFrameFilter.java deleted file mode 100644 index 3cd61a5d95f8..000000000000 --- a/java/execution/openapi/src/com/intellij/execution/filters/ReflectionStackFrameFilter.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.intellij.execution.filters; - -/** - * @author peter - */ -public class ReflectionStackFrameFilter extends StackFrameFilter { - public boolean isAuxiliaryFrame(String className, String methodName) { - if (className.equals("java.lang.reflect.Method") && methodName.equals("invoke")) { - return true; - } - if (className.equals("java.lang.reflect.Constructor") && methodName.equals("newInstance")) { - return true; - } - - return className.startsWith("sun.reflect."); - } -} diff --git a/java/execution/openapi/src/com/intellij/execution/filters/StackFrameFilter.java b/java/execution/openapi/src/com/intellij/execution/filters/StackFrameFilter.java deleted file mode 100644 index 25f6cdb1b07c..000000000000 --- a/java/execution/openapi/src/com/intellij/execution/filters/StackFrameFilter.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.intellij.execution.filters; - -import com.intellij.openapi.extensions.ExtensionPointName; - -/** - * @author peter - */ -public abstract class StackFrameFilter { - public static final ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.stackFrameFilter"); - - public abstract boolean isAuxiliaryFrame(String className, String methodName); - -} diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/actions/NewModuleAction.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/actions/NewModuleAction.java index eccd2d3a32fd..a5d578396ebb 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/actions/NewModuleAction.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/actions/NewModuleAction.java @@ -40,7 +40,7 @@ public class NewModuleAction extends AnAction implements DumbAware { } public void actionPerformed(AnActionEvent e) { - final Project project = getProject(e); + final Project project = getEventProject(e); if (project == null) { return; } @@ -88,12 +88,6 @@ public class NewModuleAction extends AnAction implements DumbAware { public void update(AnActionEvent e) { super.update(e); - e.getPresentation().setEnabled(getProject(e) != null); + e.getPresentation().setEnabled(getEventProject(e) != null); } - - @Nullable - private static Project getProject(AnActionEvent e) { - return e.getData(PlatformDataKeys.PROJECT); - } - } diff --git a/java/java-impl/src/com/intellij/codeInsight/ChangeContextUtil.java b/java/java-impl/src/com/intellij/codeInsight/ChangeContextUtil.java index be7b52124491..cc5ccf8441c5 100644 --- a/java/java-impl/src/com/intellij/codeInsight/ChangeContextUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/ChangeContextUtil.java @@ -1,4 +1,3 @@ - /* * Copyright 2000-2009 JetBrains s.r.o. * @@ -24,6 +23,7 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.refactoring.util.FieldConflictsResolver; import com.intellij.refactoring.util.RefactoringUtil; import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public class ChangeContextUtil { @@ -112,28 +112,28 @@ public class ChangeContextUtil { } } - public static PsiElement decodeContextInfo(PsiElement scope, - PsiClass thisClass, + public static PsiElement decodeContextInfo(@NotNull PsiElement scope, + @Nullable PsiClass thisClass, @Nullable PsiExpression thisAccessExpr) throws IncorrectOperationException { - if (scope.getCopyableUserData(ENCODED_KEY) != null){ + if (scope.getCopyableUserData(ENCODED_KEY) != null) { scope.putCopyableUserData(ENCODED_KEY, null); - if (scope instanceof PsiThisExpression){ + if (scope instanceof PsiThisExpression) { PsiThisExpression thisExpr = (PsiThisExpression)scope; scope = decodeThisExpression(thisExpr, thisClass, thisAccessExpr); } - else if (scope instanceof PsiReferenceExpression){ + else if (scope instanceof PsiReferenceExpression) { scope = decodeReferenceExpression((PsiReferenceExpression)scope, thisAccessExpr, thisClass); } else { PsiClass refClass = scope.getCopyableUserData(REF_CLASS_KEY); scope.putCopyableUserData(REF_CLASS_KEY, null); - if (refClass != null && refClass.isValid()){ + if (refClass != null && refClass.isValid()) { PsiReference ref = scope.getReference(); if (ref != null) { final String qualifiedName = refClass.getQualifiedName(); - if (qualifiedName != null){ + if (qualifiedName != null) { if (JavaPsiFacade.getInstance(refClass.getProject()).findClass(qualifiedName, scope.getResolveScope()) != null) { scope = ref.bindToElement(refClass); } @@ -143,14 +143,15 @@ public class ChangeContextUtil { } } - if (scope instanceof PsiClass){ - if (thisAccessExpr != null){ + if (scope instanceof PsiClass) { + if (thisAccessExpr != null) { thisAccessExpr = (PsiExpression)qualifyThis(thisAccessExpr, thisClass); } } - for(PsiElement child = scope.getFirstChild(); child != null; child = child.getNextSibling()){ - child = decodeContextInfo(child, thisClass, thisAccessExpr); + PsiElement child = scope.getFirstChild(); + while (child != null) { + child = decodeContextInfo(child, thisClass, thisAccessExpr).getNextSibling(); } return scope; diff --git a/java/java-impl/src/com/intellij/codeInsight/CodeInsightUtil.java b/java/java-impl/src/com/intellij/codeInsight/CodeInsightUtil.java index a3d28c1a5aa6..7b83ace2eada 100644 --- a/java/java-impl/src/com/intellij/codeInsight/CodeInsightUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/CodeInsightUtil.java @@ -302,17 +302,19 @@ public class CodeInsightUtil { return ApplicationManager.getApplication().runReadAction(new Computable() { public Boolean compute() { - if (!context.isValid() || !inheritor.isValid() || !facade.getResolveHelper().isAccessible(inheritor, context, null)) return true; + if (!context.isValid() || !inheritor.isValid() || !facade.getResolveHelper().isAccessible(inheritor, context, null)) + return true; - if(inheritor.getQualifiedName() == null && !manager.areElementsEquivalent(inheritor.getContainingFile(), context.getContainingFile().getOriginalFile())){ + if (inheritor.getQualifiedName() == null && + !manager.areElementsEquivalent(inheritor.getContainingFile(), context.getContainingFile().getOriginalFile())) { return true; } if (JavaCompletionUtil.isInExcludedPackage(inheritor)) return true; PsiSubstitutor superSubstitutor = TypeConversionUtil.getClassSubstitutor(baseClass, inheritor, PsiSubstitutor.EMPTY); - if(superSubstitutor == null) return true; - if(getRawSubtypes){ + if (superSubstitutor == null) return true; + if (getRawSubtypes) { result.add(createType(inheritor, facade.getElementFactory().createRawSubstitutor(inheritor), arrayDim)); return true; } @@ -322,7 +324,10 @@ public class CodeInsightUtil { for (PsiTypeParameter baseParameter : PsiUtil.typeParametersIterable(baseClass)) { final PsiType substituted = superSubstitutor.substitute(baseParameter); PsiType arg = baseSubstitutor.substitute(baseParameter); - if (arg instanceof PsiWildcardType) arg = ((PsiWildcardType)arg).getExtendsBound(); + if (arg instanceof PsiWildcardType) { + PsiType bound = ((PsiWildcardType)arg).getBound(); + arg = bound != null ? bound : ((PsiWildcardType)arg).getExtendsBound(); + } PsiType substitution = resolveHelper.getSubstitutionForTypeParameter(inheritorParameter, substituted, arg, diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java index a63b81fe9e5e..6eb834e8870a 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java @@ -50,10 +50,7 @@ import com.intellij.util.ProcessingContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Arrays; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.Set; +import java.util.*; import static com.intellij.patterns.PsiJavaPatterns.*; @@ -198,7 +195,6 @@ public class JavaCompletionContributor extends CompletionContributor { return; } - final CompletionResultSet result = JavaCompletionSorting.addJavaSorting(parameters, _result); if (ANNOTATION_ATTRIBUTE_NAME.accepts(position)) { @@ -216,10 +212,17 @@ public class JavaCompletionContributor extends CompletionContributor { result.addElement(LookupElementBuilder.create("*")); } - addReferenceVariants(parameters, result, inheritors); + Set usedWords = addReferenceVariants(parameters, result, inheritors); addKeywords(parameters, result); + if (psiElement().inside(PsiLiteralExpression.class).accepts(position)) { + PsiReference reference = position.getContainingFile().findReferenceAt(parameters.getOffset()); + if (reference == null || reference.isSoft()) { + WordCompletionContributor.addWordCompletionVariants(result, parameters, usedWords); + } + } + addAllClasses(parameters, result, inheritors); result.stopHere(); } @@ -239,7 +242,8 @@ public class JavaCompletionContributor extends CompletionContributor { } } - private static void addReferenceVariants(final CompletionParameters parameters, CompletionResultSet result, final InheritorsHolder inheritors) { + private static Set addReferenceVariants(final CompletionParameters parameters, CompletionResultSet result, final InheritorsHolder inheritors) { + final Set usedWords = new HashSet(); final PsiElement position = parameters.getPosition(); final boolean checkAccess = parameters.getInvocationCount() <= 1; LegacyCompletionContributor.processReferences(parameters, result, new PairConsumer() { @@ -291,19 +295,25 @@ public class JavaCompletionContributor extends CompletionContributor { LOG.error("Position=" + position + "\n;Reference=" + reference + "\n;variants=" + Arrays.toString(variants)); } if (completion instanceof LookupElement && !inheritors.alreadyProcessed((LookupElement)completion)) { + usedWords.add(((LookupElement)completion).getLookupString()); result.addElement((LookupElement)completion); } else if (completion instanceof PsiClass) { if (!inheritors.alreadyProcessed((PsiClass)completion)) { - result.addElement(JavaClassNameCompletionContributor.createClassLookupItem((PsiClass)completion, true)); + JavaPsiClassReferenceElement item = JavaClassNameCompletionContributor.createClassLookupItem((PsiClass)completion, true); + usedWords.add(item.getLookupString()); + result.addElement(item); } } else { - result.addElement(LookupItemUtil.objectToLookupItem(completion)); + LookupElement element = LookupItemUtil.objectToLookupItem(completion); + usedWords.add(element.getLookupString()); + result.addElement(element); } } } }); + return usedWords; } private static void addKeywords(CompletionParameters parameters, CompletionResultSet result) { diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/actions/SuppressFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/actions/SuppressFix.java index f647d669e1ca..c8ff3bed488d 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/actions/SuppressFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/actions/SuppressFix.java @@ -140,7 +140,8 @@ public class SuppressFix extends SuppressIntentionAction { if (newAnnotation != null) { if (annotation != null && annotation.isPhysical()) { annotation.replace(newAnnotation); - } else { + } + else { final PsiNameValuePair[] attributes = newAnnotation.getParameterList().getAttributes(); new AddAnnotationFix(SuppressManager.SUPPRESS_INSPECTIONS_ANNOTATION_NAME, modifierOwner, attributes).invoke(project, editor, container.getContainingFile()); } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java index f8c016341883..02866d216848 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java @@ -990,7 +990,7 @@ public class HighlightUtil { HighlightInfo errorResult = null; if (expression != null && expression.getType() != null) { PsiType type = expression.getType(); - if (!isValidTypeForSwitchSelector(type, expression)) { + if (!isValidTypeForSwitchSelector(type, PsiUtil.isLanguageLevel7OrHigher(expression))) { String message = JavaErrorMessages.message("incompatible.types", JavaErrorMessages.message("valid.switch.selector.types"), formatType(type)); errorResult = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expression, message); @@ -1002,7 +1002,7 @@ public class HighlightUtil { return errorResult; } - private static boolean isValidTypeForSwitchSelector(PsiType type, PsiExpression expression) { + public static boolean isValidTypeForSwitchSelector(PsiType type, final boolean languageLevel7OrHigher) { if (TypeConversionUtil.getTypeRank(type) <= TypeConversionUtil.INT_RANK) return true; if (type instanceof PsiClassType) { PsiClass psiClass = ((PsiClassType)type).resolve(); @@ -1010,7 +1010,7 @@ public class HighlightUtil { if (psiClass.isEnum()) { return true; } - if (PsiUtil.isLanguageLevel7OrHigher(expression)) { + if (languageLevel7OrHigher) { return Comparing.strEqual(psiClass.getQualifiedName(), CommonClassNames.JAVA_LANG_STRING); } } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AccessStaticViaInstanceFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AccessStaticViaInstanceFix.java index 93811cb51981..baa316044e8d 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AccessStaticViaInstanceFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AccessStaticViaInstanceFix.java @@ -32,6 +32,7 @@ import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.project.Project; import com.intellij.psi.*; +import com.intellij.psi.util.PsiExpressionTrimRenderer; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.PsiUtilBase; @@ -113,7 +114,7 @@ public class AccessStaticViaInstanceFix implements LocalQuickFix { qualifiedWithClassName.setQualifierExpression(factory.createReferenceExpression(containingClass)); final boolean canCopeWithSideEffects = hasSideEffects; final SideEffectWarningDialog dialog = - new SideEffectWarningDialog(project, false, null, sideEffects.get(0).getText(), qualifierExpression.getText(), + new SideEffectWarningDialog(project, false, null, sideEffects.get(0).getText(), PsiExpressionTrimRenderer.render(qualifierExpression), canCopeWithSideEffects){ @Override protected String sideEffectsDescription() { diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/RemoveUnusedVariableFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/RemoveUnusedVariableFix.java index b1fbc12df379..248008af096b 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/RemoveUnusedVariableFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/RemoveUnusedVariableFix.java @@ -28,6 +28,7 @@ import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.util.InheritanceUtil; +import com.intellij.psi.util.PsiExpressionTrimRenderer; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.PsiUtilBase; import com.intellij.refactoring.psi.PropertyUtils; @@ -149,7 +150,18 @@ public class RemoveUnusedVariableFix implements IntentionAction { PsiVariable variable, Editor editor, boolean canCopeWithSideEffects) { - String text = sideEffects.isEmpty() ? "" : sideEffects.get(0).getText(); + String text; + if (sideEffects.isEmpty()) { + text = ""; + } + else { + final PsiElement sideEffect = sideEffects.get(0); + if (sideEffect instanceof PsiExpression) { + text = PsiExpressionTrimRenderer.render((PsiExpression)sideEffect); + } else { + text = sideEffect.getText(); + } + } return showSideEffectsWarning(sideEffects, variable, editor, canCopeWithSideEffects, text, text); } diff --git a/java/java-impl/src/com/intellij/codeInsight/editorActions/smartEnter/MissingReturnExpressionFixer.java b/java/java-impl/src/com/intellij/codeInsight/editorActions/smartEnter/MissingReturnExpressionFixer.java index c117dcd8503c..df86f53a19c0 100644 --- a/java/java-impl/src/com/intellij/codeInsight/editorActions/smartEnter/MissingReturnExpressionFixer.java +++ b/java/java-impl/src/com/intellij/codeInsight/editorActions/smartEnter/MissingReturnExpressionFixer.java @@ -33,18 +33,18 @@ public class MissingReturnExpressionFixer implements Fixer { throws IncorrectOperationException { if (psiElement instanceof PsiReturnStatement) { PsiReturnStatement retStatement = (PsiReturnStatement) psiElement; - if (retStatement.getReturnValue() != null && - startLine(editor, retStatement) == startLine(editor, retStatement.getReturnValue())) { + PsiExpression returnValue = retStatement.getReturnValue(); + if (returnValue != null && + lineNumber(editor, editor.getCaretModel().getOffset()) == lineNumber(editor, returnValue.getTextRange().getStartOffset())) { return; } PsiElement parent = PsiTreeUtil.getParentOfType(psiElement, PsiClassInitializer.class, PsiMethod.class); if (parent instanceof PsiMethod) { - PsiMethod method = (PsiMethod) parent; - final PsiType returnType = method.getReturnType(); + final PsiType returnType = ((PsiMethod) parent).getReturnType(); if (returnType != null && returnType != PsiType.VOID) { final int startOffset = retStatement.getTextRange().getStartOffset(); - if (retStatement.getReturnValue() != null) { + if (returnValue != null) { editor.getDocument().insertString(startOffset + "return".length(), ";"); } @@ -54,7 +54,7 @@ public class MissingReturnExpressionFixer implements Fixer { } } - private int startLine(Editor editor, PsiElement psiElement) { - return editor.getDocument().getLineNumber(psiElement.getTextRange().getStartOffset()); + private static int lineNumber(Editor editor, int offset) { + return editor.getDocument().getLineNumber(offset); } } diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/AddAnnotationFix.java b/java/java-impl/src/com/intellij/codeInsight/intention/AddAnnotationFix.java index 0088f7be3f7f..2d31bbb0971d 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/AddAnnotationFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/AddAnnotationFix.java @@ -20,71 +20,59 @@ import com.intellij.codeInsight.AnnotationUtil; import com.intellij.codeInsight.CodeInsightBundle; import com.intellij.codeInsight.CodeInsightUtilBase; import com.intellij.codeInsight.ExternalAnnotationsManager; -import com.intellij.codeInspection.LocalQuickFix; -import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement; import com.intellij.lang.findUsages.FindUsagesProvider; import com.intellij.lang.findUsages.LanguageFindUsages; import com.intellij.openapi.command.undo.UndoUtil; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.CaretModel; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.psi.*; -import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; -import com.intellij.util.IncorrectOperationException; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** * @author ven */ -public class AddAnnotationFix extends PsiElementBaseIntentionAction implements LocalQuickFix { - private final String myAnnotation; - private final PsiModifierListOwner myModifierListOwner; +public class AddAnnotationFix extends LocalQuickFixAndIntentionActionOnPsiElement { + protected final String myAnnotation; private final String[] myAnnotationsToRemove; - private final PsiNameValuePair[] myPairs; + private final PsiNameValuePair[] myPairs; // not used when registering local quick fix private static final Logger LOG = Logger.getInstance("#" + AddAnnotationFix.class.getName()); + private final String myText; - public AddAnnotationFix(String fqn, PsiModifierListOwner modifierListOwner, String... annotationsToRemove) { - myAnnotation = fqn; - myModifierListOwner = modifierListOwner; - myAnnotationsToRemove = annotationsToRemove; - myPairs = null; + public AddAnnotationFix(@NotNull String fqn, @NotNull PsiModifierListOwner modifierListOwner, @NotNull String... annotationsToRemove) { + this(fqn, modifierListOwner, PsiNameValuePair.EMPTY_ARRAY, annotationsToRemove); } - public AddAnnotationFix(String fqn, PsiModifierListOwner modifierListOwner, PsiNameValuePair[] values, String... annotationsToRemove) { + public AddAnnotationFix(@NotNull String fqn, @NotNull PsiModifierListOwner modifierListOwner, @NotNull PsiNameValuePair[] values, @NotNull String... annotationsToRemove) { + super(modifierListOwner); myAnnotation = fqn; - myModifierListOwner = modifierListOwner; myAnnotationsToRemove = annotationsToRemove; myPairs = values; + + myText = calcText(modifierListOwner, myAnnotation); } - public AddAnnotationFix(@NonNls final String fqn, @NonNls String... annotationsToRemove) { - this(fqn, null,annotationsToRemove); + public static String calcText(PsiModifierListOwner modifierListOwner, @NotNull String annotation) { + final String shortName = annotation.substring(annotation.lastIndexOf('.') + 1); + if (modifierListOwner instanceof PsiNamedElement) { + final String name = ((PsiNamedElement)modifierListOwner).getName(); + if (name != null) { + FindUsagesProvider provider = LanguageFindUsages.INSTANCE.forLanguage(modifierListOwner.getLanguage()); + return CodeInsightBundle + .message("inspection.i18n.quickfix.annotate.element.as", provider.getType(modifierListOwner), name, shortName); + } + } + return CodeInsightBundle.message("inspection.i18n.quickfix.annotate.as", shortName); } @NotNull public String getText() { - final String shortName = myAnnotation.substring(myAnnotation.lastIndexOf('.') + 1); - if (myModifierListOwner instanceof PsiNamedElement) { - final String name = ((PsiNamedElement)myModifierListOwner).getName(); - if (name != null) { - FindUsagesProvider provider = LanguageFindUsages.INSTANCE.forLanguage(myModifierListOwner.getLanguage()); - return CodeInsightBundle.message("inspection.i18n.quickfix.annotate.element.as", provider.getType(myModifierListOwner), name, shortName); - } - } - return myModifierListOwner != null ? - CodeInsightBundle.message("inspection.i18n.quickfix.annotate.as", shortName) : - CodeInsightBundle.message("add.external.annotation.test", shortName); - } - - @NotNull - public String getName() { - return getText(); + return myText; } @NotNull @@ -92,17 +80,13 @@ public class AddAnnotationFix extends PsiElementBaseIntentionAction implements L return CodeInsightBundle.message("intention.add.annotation.family"); } - public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { - try { - invoke(project, null, descriptor.getPsiElement().getContainingFile()); - } - catch (IncorrectOperationException e) { - LOG.error(e); - } + @Override + public boolean startInWriteAction() { + return true; } @Nullable - protected static PsiModifierListOwner getContainer(final PsiElement element) { + public static PsiModifierListOwner getContainer(final PsiElement element) { PsiModifierListOwner listOwner = PsiTreeUtil.getParentOfType(element, PsiParameter.class, false); if (listOwner == null) { final PsiIdentifier psiIdentifier = PsiTreeUtil.getParentOfType(element, PsiIdentifier.class, false); @@ -113,86 +97,60 @@ public class AddAnnotationFix extends PsiElementBaseIntentionAction implements L return listOwner; } - public boolean isAvailable(@NotNull final Project project, final Editor editor, @NotNull final PsiElement element) { - if (!element.isValid()) return false; - if (!PsiUtil.isLanguageLevel5OrHigher(element)) return false; - final PsiModifierListOwner owner; - if (myModifierListOwner != null) { - if (!myModifierListOwner.isValid()) return false; - //if (!PsiManager.getInstance(project).isInProject(myModifierListOwner) - // || myModifierListOwner.getModifierList() == null) { - // if (!myModifierListOwner.isPhysical()) { //we might want to apply fix to just created method - // return true; - // } - //} - - owner = myModifierListOwner; - } - else if (!element.getManager().isInProject(element) || CodeStyleSettingsManager.getSettings(project).USE_EXTERNAL_ANNOTATIONS) { - owner = getContainer(element); - } - else { - owner = null; - } - return owner != null && !AnnotationUtil.isAnnotated(owner, myAnnotation, false); + @Override + public boolean isAvailable(@NotNull Project project, + @NotNull PsiFile file, + @NotNull PsiElement startElement, + @NotNull PsiElement endElement) { + if (!startElement.isValid()) return false; + if (!PsiUtil.isLanguageLevel5OrHigher(startElement)) return false; + final PsiModifierListOwner myModifierListOwner = (PsiModifierListOwner)startElement; + + return !AnnotationUtil.isAnnotated(myModifierListOwner, myAnnotation, false); } @Override - public boolean isAvailable(@NotNull final Project project, final Editor editor, final PsiFile file) { - final PsiElement element; - if (myModifierListOwner != null) { - element = myModifierListOwner; - } - else { - final CaretModel caretModel = editor.getCaretModel(); - final int position = caretModel.getOffset(); - element = file.findElementAt(position); - } - return element != null && isAvailable(project, editor, element); - } + public void invoke(@NotNull Project project, + @NotNull PsiFile file, + @Nullable("is null when called from inspection") Editor editor, + @NotNull PsiElement startElement, + @NotNull PsiElement endElement) { + final PsiModifierListOwner myModifierListOwner = (PsiModifierListOwner)startElement; - public void invoke(@NotNull final Project project, Editor editor, PsiFile file) throws IncorrectOperationException { final ExternalAnnotationsManager annotationsManager = ExternalAnnotationsManager.getInstance(project); - if (myModifierListOwner != null) { - final PsiModifierList modifierList = myModifierListOwner.getModifierList(); - LOG.assertTrue(modifierList != null); - if (modifierList.findAnnotation(myAnnotation) != null) return; - final ExternalAnnotationsManager.AnnotationPlace annotationAnnotationPlace = annotationsManager.chooseAnnotationsPlace(myModifierListOwner); - if (annotationAnnotationPlace == ExternalAnnotationsManager.AnnotationPlace.NOWHERE) return; - if (annotationAnnotationPlace == ExternalAnnotationsManager.AnnotationPlace.EXTERNAL) { - for (String fqn : myAnnotationsToRemove) { - annotationsManager.deannotate(myModifierListOwner, fqn); - } - annotationsManager.annotateExternally(myModifierListOwner, myAnnotation, file, myPairs); - } - else { - final PsiFile containingFile = myModifierListOwner.getContainingFile(); - if (!CodeInsightUtilBase.preparePsiElementForWrite(containingFile)) return; - for (String fqn : myAnnotationsToRemove) { - PsiAnnotation annotation = AnnotationUtil.findAnnotation(myModifierListOwner, fqn); - if (annotation != null) { - annotation.delete(); - } - } - - final @NotNull PsiAnnotation inserted = modifierList.addAnnotation(myAnnotation); - if (myPairs != null) { - for (PsiNameValuePair pair : myPairs) { - inserted.setDeclaredAttributeValue(pair.getName(), pair.getValue()); - } - } - JavaCodeStyleManager.getInstance(project).shortenClassReferences(inserted); - if (containingFile != file) { - UndoUtil.markPsiFileForUndo(file); - } + final PsiModifierList modifierList = myModifierListOwner.getModifierList(); + LOG.assertTrue(modifierList != null); + if (modifierList.findAnnotation(myAnnotation) != null) return; + final ExternalAnnotationsManager.AnnotationPlace annotationAnnotationPlace = annotationsManager.chooseAnnotationsPlace(myModifierListOwner); + if (annotationAnnotationPlace == ExternalAnnotationsManager.AnnotationPlace.NOWHERE) return; + if (annotationAnnotationPlace == ExternalAnnotationsManager.AnnotationPlace.EXTERNAL) { + for (String fqn : myAnnotationsToRemove) { + annotationsManager.deannotate(myModifierListOwner, fqn); } + annotationsManager.annotateExternally(myModifierListOwner, myAnnotation, file, myPairs); } else { - final PsiElement element = file.findElementAt(editor.getCaretModel().getOffset()); - annotationsManager.annotateExternally(PsiTreeUtil.getParentOfType(element, PsiModifierListOwner.class, false), myAnnotation, file, null); + final PsiFile containingFile = myModifierListOwner.getContainingFile(); + if (!CodeInsightUtilBase.preparePsiElementForWrite(containingFile)) return; + for (String fqn : myAnnotationsToRemove) { + PsiAnnotation annotation = AnnotationUtil.findAnnotation(myModifierListOwner, fqn); + if (annotation != null) { + annotation.delete(); + } + } + + PsiAnnotation inserted = modifierList.addAnnotation(myAnnotation); + for (PsiNameValuePair pair : myPairs) { + inserted.setDeclaredAttributeValue(pair.getName(), pair.getValue()); + } + JavaCodeStyleManager.getInstance(project).shortenClassReferences(inserted); + if (containingFile != file) { + UndoUtil.markPsiFileForUndo(file); + } } } + @NotNull public String[] getAnnotationsToRemove() { return myAnnotationsToRemove; } diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddAnnotationIntention.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddAnnotationIntention.java new file mode 100644 index 000000000000..c115b96f83ce --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddAnnotationIntention.java @@ -0,0 +1,96 @@ +/* + * 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. + */ + +/* + * Created by IntelliJ IDEA. + * User: cdr + * Date: Jul 20, 2007 + * Time: 2:57:38 PM + */ +package com.intellij.codeInsight.intention.impl; + +import com.intellij.codeInsight.AnnotationUtil; +import com.intellij.codeInsight.CodeInsightBundle; +import com.intellij.codeInsight.intention.AddAnnotationFix; +import com.intellij.openapi.editor.CaretModel; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pair; +import com.intellij.psi.*; +import com.intellij.psi.codeStyle.CodeStyleSettingsManager; +import com.intellij.psi.util.PsiUtil; +import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; + +public abstract class AddAnnotationIntention extends BaseIntentionAction { + @NotNull + @Override + public String getFamilyName() { + return CodeInsightBundle.message("intention.add.annotation.family"); + } + + @NotNull + public abstract Pair getAnnotations(@NotNull Project project); + + // include not in project files + public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { + CaretModel caretModel = editor.getCaretModel(); + int position = caretModel.getOffset(); + PsiElement element = file.findElementAt(position); + return element != null && isAvailable(project, element); + } + + public boolean isAvailable(@NotNull final Project project, @NotNull final PsiElement element) { + if (!element.isValid()) return false; + if (!PsiUtil.isLanguageLevel5OrHigher(element)) return false; + final PsiModifierListOwner owner; + if (!element.getManager().isInProject(element) || CodeStyleSettingsManager.getSettings(project).USE_EXTERNAL_ANNOTATIONS) { + owner = AddAnnotationFix.getContainer(element); + } + else { + return false; + } + if (owner == null) return false; + Pair annotations = getAnnotations(project); + String toAdd = annotations.first; + String[] toRemove = annotations.second; + if (toRemove.length > 0 && AnnotationUtil.isAnnotated(owner, toRemove[0], false)) return false; + setText(AddAnnotationFix.calcText(owner, toAdd)); + if (AnnotationUtil.isAnnotated(owner, toAdd, false)) return false; + + if (owner instanceof PsiMethod) { + PsiType returnType = ((PsiMethod)owner).getReturnType(); + + return returnType != null && !(returnType instanceof PsiPrimitiveType); + } + return true; + } + + @Override + public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { + CaretModel caretModel = editor.getCaretModel(); + int position = caretModel.getOffset(); + PsiElement element = file.findElementAt(position); + + PsiModifierListOwner owner = AddAnnotationFix.getContainer(element); + if (owner == null || !owner.isValid()) return; + Pair annotations = getAnnotations(project); + String toAdd = annotations.first; + String[] toRemove = annotations.second; + AddAnnotationFix fix = new AddAnnotationFix(toAdd, owner, toRemove); + fix.invoke(project, editor, file); + } +} \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddDeprecationAnnotationFix.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddDeprecationAnnotationIntention.java similarity index 51% rename from java/java-impl/src/com/intellij/codeInsight/intention/impl/AddDeprecationAnnotationFix.java rename to java/java-impl/src/com/intellij/codeInsight/intention/impl/AddDeprecationAnnotationIntention.java index c8e21c39d886..bcc4e4c1cb5d 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddDeprecationAnnotationFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddDeprecationAnnotationIntention.java @@ -22,32 +22,15 @@ */ package com.intellij.codeInsight.intention.impl; -import com.intellij.codeInsight.intention.AddAnnotationFix; -import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; -import com.intellij.psi.*; +import com.intellij.openapi.util.Pair; +import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NotNull; -public class AddDeprecationAnnotationFix extends AddAnnotationFix { - public AddDeprecationAnnotationFix() { - super("java.lang.annotation.Deprecated"); - } - - +public class AddDeprecationAnnotationIntention extends AddAnnotationIntention { + @NotNull @Override - public boolean isAvailable(@NotNull final Project project, final Editor editor, @NotNull final PsiElement element) { - if (!super.isAvailable(project, editor, element)) { - return false; - } - PsiModifierListOwner owner = getContainer(element); - if (owner == null) { - return false; - } - if (owner instanceof PsiMethod) { - PsiType returnType = ((PsiMethod)owner).getReturnType(); - - return returnType != null && !(returnType instanceof PsiPrimitiveType); - } - return true; + public Pair getAnnotations(@NotNull Project project) { + return new Pair("java.lang.annotation.Deprecated", ArrayUtil.EMPTY_STRING_ARRAY); } } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddNotNullAnnotationFix.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddNotNullAnnotationFix.java index 86a23fcce8f1..dd04cd154ded 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddNotNullAnnotationFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddNotNullAnnotationFix.java @@ -22,26 +22,23 @@ */ package com.intellij.codeInsight.intention.impl; -import com.intellij.codeInsight.AnnotationUtil; import com.intellij.codeInsight.NullableNotNullManager; import com.intellij.psi.PsiModifierListOwner; import com.intellij.util.ArrayUtil; +import org.jetbrains.annotations.NotNull; import java.util.List; public class AddNotNullAnnotationFix extends AddNullableNotNullAnnotationFix { - @Deprecated - public AddNotNullAnnotationFix() { - super(AnnotationUtil.NOT_NULL, AnnotationUtil.NULLABLE); - } - public AddNotNullAnnotationFix(PsiModifierListOwner owner) { + public AddNotNullAnnotationFix(@NotNull PsiModifierListOwner owner) { super(NullableNotNullManager.getInstance(owner.getProject()).getDefaultNotNull(), owner, getNullables(owner)); } - private static String[] getNullables(PsiModifierListOwner owner) { + @NotNull + private static String[] getNullables(@NotNull PsiModifierListOwner owner) { final List nullables = NullableNotNullManager.getInstance(owner.getProject()).getNullables(); return ArrayUtil.toStringArray(nullables); } -} \ No newline at end of file +} diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddNotNullAnnotationIntention.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddNotNullAnnotationIntention.java new file mode 100644 index 000000000000..b5e322503b4c --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddNotNullAnnotationIntention.java @@ -0,0 +1,45 @@ +/* + * 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. + */ + +/* + * Created by IntelliJ IDEA. + * User: cdr + * Date: Jul 20, 2007 + * Time: 2:57:38 PM + */ +package com.intellij.codeInsight.intention.impl; + +import com.intellij.codeInsight.NullableNotNullManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pair; +import com.intellij.util.ArrayUtil; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public class AddNotNullAnnotationIntention extends AddAnnotationIntention { + @NotNull + @Override + public Pair getAnnotations(@NotNull Project project) { + return new Pair(NullableNotNullManager.getInstance(project).getDefaultNotNull(), getNullables(project)); + } + + @NotNull + private static String[] getNullables(@NotNull Project project) { + final List nullables = NullableNotNullManager.getInstance(project).getNullables(); + return ArrayUtil.toStringArray(nullables); + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddNullableAnnotationFix.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddNullableAnnotationFix.java index cc995bf84509..9d6a4f1057b1 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddNullableAnnotationFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddNullableAnnotationFix.java @@ -22,26 +22,22 @@ */ package com.intellij.codeInsight.intention.impl; -import com.intellij.codeInsight.AnnotationUtil; import com.intellij.codeInsight.NullableNotNullManager; import com.intellij.psi.PsiModifierListOwner; import com.intellij.util.ArrayUtil; +import org.jetbrains.annotations.NotNull; import java.util.List; public class AddNullableAnnotationFix extends AddNullableNotNullAnnotationFix { - @Deprecated - public AddNullableAnnotationFix() { - super(AnnotationUtil.NULLABLE, AnnotationUtil.NOT_NULL); - } - - public AddNullableAnnotationFix(PsiModifierListOwner owner) { + public AddNullableAnnotationFix(@NotNull PsiModifierListOwner owner) { super(NullableNotNullManager.getInstance(owner.getProject()).getDefaultNullable(), owner, getNotNulls(owner)); } - private static String[] getNotNulls(PsiModifierListOwner owner) { + @NotNull + private static String[] getNotNulls(@NotNull PsiModifierListOwner owner) { final List notnulls = NullableNotNullManager.getInstance(owner.getProject()).getNotNulls(); return ArrayUtil.toStringArray(notnulls); } diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddNullableAnnotationIntention.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddNullableAnnotationIntention.java new file mode 100644 index 000000000000..3979218b069a --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddNullableAnnotationIntention.java @@ -0,0 +1,45 @@ +/* + * 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. + */ + +/* + * Created by IntelliJ IDEA. + * User: cdr + * Date: Jul 20, 2007 + * Time: 2:57:59 PM + */ +package com.intellij.codeInsight.intention.impl; + +import com.intellij.codeInsight.NullableNotNullManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pair; +import com.intellij.util.ArrayUtil; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public class AddNullableAnnotationIntention extends AddAnnotationIntention { + @NotNull + @Override + public Pair getAnnotations(@NotNull Project project) { + return new Pair(NullableNotNullManager.getInstance(project).getDefaultNullable(), getNotNulls(project)); + } + + @NotNull + private static String[] getNotNulls(@NotNull Project project) { + final List notnulls = NullableNotNullManager.getInstance(project).getNotNulls(); + return ArrayUtil.toStringArray(notnulls); + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddNullableNotNullAnnotationFix.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddNullableNotNullAnnotationFix.java index 30428a04233d..fee586a57aee 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddNullableNotNullAnnotationFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddNullableNotNullAnnotationFix.java @@ -24,26 +24,24 @@ package com.intellij.codeInsight.intention.impl; import com.intellij.codeInsight.AnnotationUtil; import com.intellij.codeInsight.intention.AddAnnotationFix; -import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import org.jetbrains.annotations.NotNull; public class AddNullableNotNullAnnotationFix extends AddAnnotationFix { - public AddNullableNotNullAnnotationFix(final String annotation, final String... annotationToRemove) { - super(annotation, annotationToRemove); - } - - public AddNullableNotNullAnnotationFix(final String fqn, final PsiModifierListOwner owner, final String... annotationToRemove) { + public AddNullableNotNullAnnotationFix(@NotNull String fqn, @NotNull PsiModifierListOwner owner, @NotNull String... annotationToRemove) { super(fqn, owner, annotationToRemove); } @Override - public boolean isAvailable(@NotNull final Project project, final Editor editor, @NotNull final PsiElement element) { - if (!super.isAvailable(project, editor, element)) { + public boolean isAvailable(@NotNull Project project, + @NotNull PsiFile file, + @NotNull PsiElement startElement, + @NotNull PsiElement endElement) { + if (!super.isAvailable(project, file, startElement, endElement)) { return false; } - PsiModifierListOwner owner = getContainer(element); + PsiModifierListOwner owner = getContainer(startElement); if (owner == null || AnnotationUtil.isAnnotated(owner, getAnnotationsToRemove()[0], false)) { return false; } diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddOverrideAnnotationAction.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddOverrideAnnotationAction.java index 8a3a22b2f791..8a3e048b54e6 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddOverrideAnnotationAction.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddOverrideAnnotationAction.java @@ -61,7 +61,9 @@ public class AddOverrideAnnotationAction implements IntentionAction { public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { PsiMethod method = findMethod(file, editor.getCaretModel().getOffset()); - new AddAnnotationFix(JAVA_LANG_OVERRIDE, method).invoke(project, editor, file); + if (method != null) { + new AddAnnotationFix(JAVA_LANG_OVERRIDE, method).invoke(project, editor, file); + } } private static PsiMethod findMethod(PsiFile file, int offset) { diff --git a/java/java-impl/src/com/intellij/codeInspection/AnnotateMethodFix.java b/java/java-impl/src/com/intellij/codeInspection/AnnotateMethodFix.java index 62949153b313..740891f12c8f 100644 --- a/java/java-impl/src/com/intellij/codeInspection/AnnotateMethodFix.java +++ b/java/java-impl/src/com/intellij/codeInspection/AnnotateMethodFix.java @@ -109,7 +109,7 @@ public class AnnotateMethodFix implements LocalQuickFix { return getName(); } - private void annotateMethod(final PsiMethod method) { + private void annotateMethod(@NotNull PsiMethod method) { try { new AddAnnotationFix(myAnnotation, method, myAnnotationsToRemove).invoke(method.getProject(), null, method.getContainingFile()); } diff --git a/java/java-impl/src/com/intellij/codeInspection/PossibleHeapPollutionVarargsInspection.java b/java/java-impl/src/com/intellij/codeInspection/PossibleHeapPollutionVarargsInspection.java index 767b932079e2..8eebe7f115ef 100644 --- a/java/java-impl/src/com/intellij/codeInspection/PossibleHeapPollutionVarargsInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/PossibleHeapPollutionVarargsInspection.java @@ -25,11 +25,9 @@ import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; import com.intellij.psi.search.searches.OverridingMethodsSearch; import com.intellij.psi.search.searches.ReferencesSearch; -import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; -import sun.util.LocaleServiceProviderPool; /** * User: anna @@ -111,7 +109,9 @@ public class PossibleHeapPollutionVarargsInspection extends BaseJavaLocalInspect final PsiElement psiElement = descriptor.getPsiElement(); if (psiElement instanceof PsiIdentifier) { final PsiMethod psiMethod = (PsiMethod)psiElement.getParent(); - new AddAnnotationFix("java.lang.SafeVarargs", psiMethod).applyFix(project, descriptor); + if (psiMethod != null) { + new AddAnnotationFix("java.lang.SafeVarargs", psiMethod).applyFix(project, descriptor); + } } } } diff --git a/java/java-impl/src/com/intellij/codeInspection/defUse/DefUseInspection.java b/java/java-impl/src/com/intellij/codeInspection/defUse/DefUseInspection.java index 106d6b6f4b3f..530363520bcb 100644 --- a/java/java-impl/src/com/intellij/codeInspection/defUse/DefUseInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/defUse/DefUseInspection.java @@ -35,6 +35,7 @@ import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.controlFlow.DefUseUtil; +import com.intellij.psi.util.PsiExpressionTrimRenderer; import com.intellij.psi.util.PsiUtil; import com.intellij.util.IncorrectOperationException; import gnu.trove.THashSet; @@ -243,7 +244,10 @@ public class DefUseInspection extends BaseLocalInspectionTool { int res = SideEffectWarningDialog.DELETE_ALL; if (hasSideEffects) { hasSideEffects = PsiUtil.isStatement(psiInitializer); - res = RemoveUnusedVariableFix.showSideEffectsWarning(sideEffects, variable, FileEditorManager.getInstance(project).getSelectedTextEditor(), hasSideEffects, sideEffects.get(0).getText(), variable.getTypeElement().getText() + " " + variable.getName() + ";
" + psiInitializer.getText()); + res = RemoveUnusedVariableFix.showSideEffectsWarning(sideEffects, variable, + FileEditorManager.getInstance(project).getSelectedTextEditor(), + hasSideEffects, sideEffects.get(0).getText(), + variable.getTypeElement().getText() + " " + variable.getName() + ";
" + PsiExpressionTrimRenderer.render((PsiExpression)psiInitializer)); } try { if (res == SideEffectWarningDialog.DELETE_ALL) { diff --git a/java/java-impl/src/com/intellij/codeInspection/nullable/AnnotateOverriddenMethodParameterFix.java b/java/java-impl/src/com/intellij/codeInspection/nullable/AnnotateOverriddenMethodParameterFix.java index 66caf769d4c0..eaca9acd2f6d 100644 --- a/java/java-impl/src/com/intellij/codeInspection/nullable/AnnotateOverriddenMethodParameterFix.java +++ b/java/java-impl/src/com/intellij/codeInspection/nullable/AnnotateOverriddenMethodParameterFix.java @@ -80,6 +80,7 @@ public class AnnotateOverriddenMethodParameterFix implements LocalQuickFix { CodeInsightUtilBase.preparePsiElementsForWrite(toAnnotate); for (PsiParameter psiParam : toAnnotate) { try { + assert psiParam != null : toAnnotate; new AddAnnotationFix(myAnnotation, psiParam, myAnnosToRemove).invoke(project, null, psiParam.getContainingFile()); } catch (IncorrectOperationException e) { @@ -92,4 +93,4 @@ public class AnnotateOverriddenMethodParameterFix implements LocalQuickFix { public String getFamilyName() { return getName(); } -} \ No newline at end of file +} diff --git a/java/java-impl/src/com/intellij/codeInspection/nullable/NullableStuffInspection.java b/java/java-impl/src/com/intellij/codeInspection/nullable/NullableStuffInspection.java index ef36d3d08461..499a3452e92d 100644 --- a/java/java-impl/src/com/intellij/codeInspection/nullable/NullableStuffInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/nullable/NullableStuffInspection.java @@ -23,11 +23,12 @@ import com.intellij.codeInsight.intention.impl.AddNotNullAnnotationFix; import com.intellij.codeInsight.intention.impl.AddNullableAnnotationFix; import com.intellij.codeInspection.*; import com.intellij.codeInspection.ex.BaseLocalInspectionTool; -import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; -import com.intellij.psi.codeStyle.*; +import com.intellij.psi.codeStyle.CodeStyleSettingsManager; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; +import com.intellij.psi.codeStyle.VariableKind; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.searches.OverridingMethodsSearch; @@ -76,13 +77,9 @@ public class NullableStuffInspection extends BaseLocalInspectionTool { for (int i = 0, expressionsLength = expressions.length; i < Math.min(expressionsLength, parameters.length); i++) { PsiExpression psiExpression = expressions[i]; if (psiExpression.getType() == PsiType.NULL) { - if (!AnnotationUtil.isNullable(parameters[i]) && !AnnotationUtil.isNotNull(parameters[i])) { - holder.registerProblem(psiExpression, "Null is passed to parameter which is not yet @Nullable", new AddNullableAnnotationFix(parameters[i]){ - @Override - public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) { - return true; - } - }); + final PsiParameter parameter = parameters[i]; + if (!AnnotationUtil.isNullable(parameter) && !AnnotationUtil.isNotNull(parameter)) { + holder.registerProblem(psiExpression, "Null is passed to parameter which is not yet @Nullable", new MyAddNullableAnnotationFix(parameter)); } } } @@ -107,21 +104,22 @@ public class NullableStuffInspection extends BaseLocalInspectionTool { final PsiMethod getter = PropertyUtil.findPropertyGetter(field.getContainingClass(), propName, isStatic, false); final String nullableSimpleName = StringUtil.getShortName(manager.getDefaultNullable()); final String notNullSimpleName = StringUtil.getShortName(manager.getDefaultNotNull()); - if (getter != null) { + final PsiIdentifier nameIdentifier = getter == null ? null : getter.getNameIdentifier(); + if (nameIdentifier != null) { if (REPORT_NOT_ANNOTATED_GETTER) { if (!AnnotationUtil.isAnnotated(getter, manager.getAllAnnotations()) && !TypeConversionUtil.isPrimitiveAndNotNull(getter.getReturnType())) { - holder.registerProblem(getter.getNameIdentifier(), InspectionsBundle + holder.registerProblem(nameIdentifier, InspectionsBundle .message("inspection.nullable.problems.annotated.field.getter.not.annotated", StringUtil.getShortName(anno)), ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new AnnotateMethodFix(anno, ArrayUtil.toStringArray(annoToRemove))); } } if (annotated.isDeclaredNotNull && manager.isNullable(getter, false)) { - holder.registerProblem(getter.getNameIdentifier(), InspectionsBundle.message( + holder.registerProblem(nameIdentifier, InspectionsBundle.message( "inspection.nullable.problems.annotated.field.getter.conflict", StringUtil.getShortName(anno), nullableSimpleName), ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new AnnotateMethodFix(anno, ArrayUtil.toStringArray(annoToRemove))); } else if (annotated.isDeclaredNullable && manager.isNotNull(getter, false)) { - holder.registerProblem(getter.getNameIdentifier(), InspectionsBundle.message( + holder.registerProblem(nameIdentifier, InspectionsBundle.message( "inspection.nullable.problems.annotated.field.getter.conflict", StringUtil.getShortName(anno), notNullSimpleName), ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new AnnotateMethodFix(anno, ArrayUtil.toStringArray(annoToRemove))); } @@ -131,23 +129,31 @@ public class NullableStuffInspection extends BaseLocalInspectionTool { final PsiMethod setter = PropertyUtil.findPropertySetter(containingClass, propName, isStatic, false); if (setter != null) { final PsiParameter[] parameters = setter.getParameterList().getParameters(); - assert parameters.length == 1; + assert parameters.length == 1 : setter.getText(); final PsiParameter parameter = parameters[0]; + assert parameter != null : setter.getText(); if (REPORT_NOT_ANNOTATED_SETTER_PARAMETER && !AnnotationUtil.isAnnotated(parameter, manager.getAllAnnotations()) && !TypeConversionUtil.isPrimitiveAndNotNull(parameter.getType())) { - holder.registerProblem(parameter.getNameIdentifier(), + final PsiIdentifier nameIdentifier1 = parameter.getNameIdentifier(); + assert nameIdentifier1 != null : parameter; + holder.registerProblem(nameIdentifier1, InspectionsBundle.message("inspection.nullable.problems.annotated.field.setter.parameter.not.annotated", StringUtil.getShortName(anno)), ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new AddAnnotationFix(anno, parameter, ArrayUtil.toStringArray(annoToRemove))); } if (annotated.isDeclaredNotNull && manager.isNullable(parameter, false)) { - holder.registerProblem(parameter.getNameIdentifier(), InspectionsBundle.message( + final PsiIdentifier nameIdentifier1 = parameter.getNameIdentifier(); + assert nameIdentifier1 != null : parameter; + holder.registerProblem(nameIdentifier1, InspectionsBundle.message( "inspection.nullable.problems.annotated.field.setter.parameter.conflict", StringUtil.getShortName(anno), nullableSimpleName), ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new AddAnnotationFix(anno, parameter, ArrayUtil.toStringArray(annoToRemove))); - } else if (annotated.isDeclaredNullable && manager.isNotNull(parameter, false)) { - holder.registerProblem(parameter.getNameIdentifier(), InspectionsBundle.message( + } + else if (annotated.isDeclaredNullable && manager.isNotNull(parameter, false)) { + final PsiIdentifier nameIdentifier1 = parameter.getNameIdentifier(); + assert nameIdentifier1 != null : parameter; + holder.registerProblem(nameIdentifier1, InspectionsBundle.message( "inspection.nullable.problems.annotated.field.setter.parameter.conflict", StringUtil.getShortName(anno), notNullSimpleName), ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new AddAnnotationFix(anno, parameter, ArrayUtil.toStringArray(annoToRemove))); @@ -187,20 +193,27 @@ public class NullableStuffInspection extends BaseLocalInspectionTool { return true; } if (REPORT_NOT_ANNOTATED_SETTER_PARAMETER && !AnnotationUtil.isAnnotated(parameter, manager.getAllAnnotations())) { - holder.registerProblem(parameter.getNameIdentifier(), InspectionsBundle + final PsiIdentifier nameIdentifier2 = parameter.getNameIdentifier(); + assert nameIdentifier2 != null : parameter; + holder.registerProblem(nameIdentifier2, InspectionsBundle .message("inspection.nullable.problems.annotated.field.constructor.parameter.not.annotated", StringUtil.getShortName(anno)), ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new AddAnnotationFix(anno, parameter, ArrayUtil.toStringArray(annoToRemove))); return true; } if (annotated.isDeclaredNotNull && manager.isNullable(parameter, false)) { - holder.registerProblem(parameter.getNameIdentifier(), InspectionsBundle.message( + final PsiIdentifier nameIdentifier2 = parameter.getNameIdentifier(); + assert nameIdentifier2 != null : parameter; + holder.registerProblem(nameIdentifier2, InspectionsBundle.message( "inspection.nullable.problems.annotated.field.constructor.parameter.conflict", StringUtil.getShortName(anno), nullableSimpleName), ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new AddAnnotationFix(anno, parameter, ArrayUtil.toStringArray(annoToRemove))); - } else if (annotated.isDeclaredNullable && manager.isNotNull(parameter, false)) { - holder.registerProblem(parameter.getNameIdentifier(), InspectionsBundle.message( + } + else if (annotated.isDeclaredNullable && manager.isNotNull(parameter, false)) { + final PsiIdentifier nameIdentifier2 = parameter.getNameIdentifier(); + assert nameIdentifier2 != null : parameter; + holder.registerProblem(nameIdentifier2, InspectionsBundle.message( "inspection.nullable.problems.annotated.field.constructor.parameter.conflict", StringUtil.getShortName(anno), notNullSimpleName), ProblemHighlightType.GENERIC_ERROR_OR_WARNING, @@ -306,14 +319,11 @@ public class NullableStuffInspection extends BaseLocalInspectionTool { && !annotated.isDeclaredNotNull && AnnotationUtil.isNotNull(superMethod)) { reported_not_annotated_method_overrides_notnull = true; + final String defaultNotNull = nullableManager.getDefaultNotNull(); + final String[] annotationsToRemove = ArrayUtil.toStringArray(nullableManager.getNullables()); holder.registerProblem(method.getNameIdentifier(), InspectionsBundle.message("inspection.nullable.problems.method.overrides.NotNull"), - ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new AnnotateMethodFix( - nullableManager.getDefaultNotNull(), ArrayUtil.toStringArray(nullableManager.getNullables())) { - public int annotateBaseMethod(final PsiMethod method, final PsiMethod superMethod, final Project project) { - return NullableStuffInspection.this.annotateBaseMethod(method, superMethod, project); - } - }); + ProblemHighlightType.GENERIC_ERROR_OR_WARNING, createAnnotateMethodFix(defaultNotNull, annotationsToRemove)); } if (REPORT_NOTNULL_PARAMETER_OVERRIDES_NULLABLE || REPORT_NOT_ANNOTATED_PARAMETER_OVERRIDES_NOTNULL) { PsiParameter[] superParameters = superMethod.getParameterList().getParameters(); @@ -366,17 +376,11 @@ public class NullableStuffInspection extends BaseLocalInspectionTool { && !nullableManager.isNotNull(overriding, false)) { method.getNameIdentifier(); //load tree PsiAnnotation annotation = AnnotationUtil.findAnnotation(method, nullableManager.getNotNulls()); + final String defaultNotNull = nullableManager.getDefaultNotNull(); + final String[] annotationsToRemove = ArrayUtil.toStringArray(nullableManager.getNullables()); holder.registerProblem(annotation, InspectionsBundle.message("nullable.stuff.problems.overridden.methods.are.not.annotated"), - ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new AnnotateMethodFix(nullableManager.getDefaultNotNull(), ArrayUtil.toStringArray(nullableManager.getNullables())){ - protected boolean annotateOverriddenMethods() { - return true; - } - - @NotNull - public String getName() { - return InspectionsBundle.message("annotate.overridden.methods.as.notnull"); - } - }); + ProblemHighlightType.GENERIC_ERROR_OR_WARNING, + new MyAnnotateMethodFix(defaultNotNull, annotationsToRemove)); methodQuickFixSuggested = true; } if (hasAnnotatedParameter) { @@ -400,9 +404,8 @@ public class NullableStuffInspection extends BaseLocalInspectionTool { } } - protected int annotateBaseMethod(final PsiMethod method, final PsiMethod superMethod, final Project project) { - final NullableNotNullManager manager = NullableNotNullManager.getInstance(project); - return new AnnotateMethodFix(manager.getDefaultNotNull(), ArrayUtil.toStringArray(manager.getNullables())).annotateBaseMethod(method, superMethod, project); + protected AnnotateMethodFix createAnnotateMethodFix(final String defaultNotNull, final String[] annotationsToRemove) { + return new AnnotateMethodFix(defaultNotNull, annotationsToRemove); } private static void reportNullableNotNullConflict(final ProblemsHolder holder, final PsiModifierListOwner listOwner, final PsiAnnotation declaredNullable, @@ -419,6 +422,35 @@ public class NullableStuffInspection extends BaseLocalInspectionTool { return new OptionsPanel(); } + private static class MyAddNullableAnnotationFix extends AddNullableAnnotationFix { + public MyAddNullableAnnotationFix(PsiParameter parameter) { + super(parameter); + } + + @Override + public boolean isAvailable(@NotNull Project project, + @NotNull PsiFile file, + @NotNull PsiElement startElement, + @NotNull PsiElement endElement) { + return true; + } + } + + private static class MyAnnotateMethodFix extends AnnotateMethodFix { + public MyAnnotateMethodFix(String defaultNotNull, String[] annotationsToRemove) { + super(defaultNotNull, annotationsToRemove); + } + + protected boolean annotateOverriddenMethods() { + return true; + } + + @NotNull + public String getName() { + return InspectionsBundle.message("annotate.overridden.methods.as.notnull"); + } + } + private class OptionsPanel extends JPanel { private JCheckBox myNNParameterOverridesN; private JCheckBox myNAMethodOverridesNN; diff --git a/java/java-impl/src/com/intellij/lang/java/JavaWordCompletionFilter.java b/java/java-impl/src/com/intellij/lang/java/JavaWordCompletionFilter.java index 0c752ae2e23b..ef0e3cb44b04 100644 --- a/java/java-impl/src/com/intellij/lang/java/JavaWordCompletionFilter.java +++ b/java/java-impl/src/com/intellij/lang/java/JavaWordCompletionFilter.java @@ -32,11 +32,6 @@ public class JavaWordCompletionFilter implements WordCompletionElementFilter { JavaDocTokenType.DOC_COMMENT_DATA, JavaTokenType.STRING_LITERAL); public boolean isWordCompletionEnabledIn(final IElementType element) { - final CompletionProcess process = CompletionService.getCompletionService().getCurrentCompletion(); - if (process != null && process.isAutopopupCompletion()) { - return false; - } - return ENABLED_TOKENS.contains(element); } } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java b/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java index f654587578f8..aed4ec8201c2 100644 --- a/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java +++ b/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java @@ -1372,7 +1372,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo ); } final boolean rBrace = isRBrace(child); - Indent childIndent = rBrace ? Indent.getNoneIndent() : getCodeBlockInternalIndent(childrenIndent, true); + Indent childIndent = rBrace ? Indent.getNoneIndent() : getCodeBlockInternalIndent(childrenIndent, false); if (!rBrace && child.getElementType() == JavaElementType.CODE_BLOCK && (getBraceStyle() == CommonCodeStyleSettings.NEXT_LINE_SHIFTED || getBraceStyle() == CommonCodeStyleSettings.NEXT_LINE_SHIFTED2)) diff --git a/java/java-impl/src/com/intellij/psi/impl/PsiJavaParserFacadeImpl.java b/java/java-impl/src/com/intellij/psi/impl/PsiJavaParserFacadeImpl.java index 42dd27340cf9..827ae506379a 100644 --- a/java/java-impl/src/com/intellij/psi/impl/PsiJavaParserFacadeImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/PsiJavaParserFacadeImpl.java @@ -170,7 +170,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ @NotNull @Override - public PsiAnnotation createAnnotationFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + public PsiAnnotation createAnnotationFromText(@NotNull final String text, @Nullable final PsiElement context) throws IncorrectOperationException { final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, ANNOTATION, level(context)), context); final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); if (!(element instanceof PsiAnnotation)) { @@ -187,7 +187,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ @NotNull @Override - public PsiDocTag createDocTagFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + public PsiDocTag createDocTagFromText(@NotNull final String text, @Nullable final PsiElement context) throws IncorrectOperationException { return createDocTagFromText(text); } @@ -202,14 +202,14 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ @NotNull @Override - public PsiDocComment createDocCommentFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + public PsiDocComment createDocCommentFromText(@NotNull final String text, @Nullable final PsiElement context) throws IncorrectOperationException { return createDocCommentFromText(text); } @NotNull @Override - public PsiClass createClassFromText(@NotNull final String body, final PsiElement context) throws IncorrectOperationException { - final PsiJavaFile aFile = createDummyJavaFile(StringUtil.join("class _Dummy_ { ", body, " }")); + public PsiClass createClassFromText(@NotNull final String body, @Nullable final PsiElement context) throws IncorrectOperationException { + final PsiJavaFile aFile = createDummyJavaFile(StringUtil.join("class _Dummy_ {\n", body, "\n}")); final PsiClass[] classes = aFile.getClasses(); if (classes.length != 1) { throw new IncorrectOperationException("Incorrect class \"" + body + "\"."); @@ -219,7 +219,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ @NotNull @Override - public PsiField createFieldFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + public PsiField createFieldFromText(@NotNull final String text, @Nullable final PsiElement context) throws IncorrectOperationException { final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, DECLARATION, level(context)), context); final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); if (!(element instanceof PsiField)) { @@ -230,7 +230,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ @NotNull @Override - public PsiMethod createMethodFromText(@NotNull final String text, final PsiElement context, final LanguageLevel level) throws IncorrectOperationException { + public PsiMethod createMethodFromText(@NotNull final String text, @Nullable final PsiElement context, final LanguageLevel level) throws IncorrectOperationException { final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, DECLARATION, level), context); final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); if (!(element instanceof PsiMethod)) { @@ -241,14 +241,14 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ @NotNull @Override - public final PsiMethod createMethodFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + public final PsiMethod createMethodFromText(@NotNull final String text, @Nullable final PsiElement context) throws IncorrectOperationException { final LanguageLevel level = LanguageLevelProjectExtension.getInstance(myManager.getProject()).getLanguageLevel(); return createMethodFromText(text, context, level); } @NotNull @Override - public PsiParameter createParameterFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + public PsiParameter createParameterFromText(@NotNull final String text, @Nullable final PsiElement context) throws IncorrectOperationException { final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, PARAMETER, level(context)), context); final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); if (!(element instanceof PsiParameter)) { @@ -259,7 +259,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ @NotNull @Override - public PsiResourceVariable createResourceFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + public PsiResourceVariable createResourceFromText(@NotNull final String text, @Nullable final PsiElement context) throws IncorrectOperationException { final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, RESOURCE, level(context)), context); final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); if (!(element instanceof PsiResourceVariable)) { @@ -270,13 +270,13 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ @NotNull @Override - public PsiType createTypeFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + public PsiType createTypeFromText(@NotNull final String text, @Nullable final PsiElement context) throws IncorrectOperationException { return createTypeInner(text, context, false); } @NotNull @Override - public PsiTypeElement createTypeElementFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + public PsiTypeElement createTypeElementFromText(@NotNull final String text, @Nullable final PsiElement context) throws IncorrectOperationException { final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, TYPE, level(context)), context); final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); if (!(element instanceof PsiTypeElement)) { @@ -285,7 +285,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ return (PsiTypeElement)element; } - protected PsiType createTypeInner(final String text, final PsiElement context, final boolean markAsCopy) throws IncorrectOperationException { + protected PsiType createTypeInner(final String text, @Nullable final PsiElement context, final boolean markAsCopy) throws IncorrectOperationException { final PsiPrimitiveType primitiveType = PRIMITIVE_TYPES.get(text); if (primitiveType != null) return primitiveType; @@ -298,7 +298,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ @NotNull @Override - public PsiJavaCodeReferenceElement createReferenceFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + public PsiJavaCodeReferenceElement createReferenceFromText(@NotNull final String text, @Nullable final PsiElement context) throws IncorrectOperationException { final boolean isStaticImport = context instanceof PsiImportStaticStatement && !((PsiImportStaticStatement)context).isOnDemand(); final boolean mayHaveDiamonds = context instanceof PsiNewExpression && @@ -314,7 +314,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ @NotNull @Override - public PsiCodeBlock createCodeBlockFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + public PsiCodeBlock createCodeBlockFromText(@NotNull final String text, @Nullable final PsiElement context) throws IncorrectOperationException { final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, CODE_BLOCK, level(context), true), context); final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); if (!(element instanceof PsiCodeBlock)) { @@ -325,7 +325,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ @NotNull @Override - public PsiStatement createStatementFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + public PsiStatement createStatementFromText(@NotNull final String text, @Nullable final PsiElement context) throws IncorrectOperationException { final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, STATEMENT, level(context)), context); final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); if (!(element instanceof PsiStatement)) { @@ -336,7 +336,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ @NotNull @Override - public PsiExpression createExpressionFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + public PsiExpression createExpressionFromText(@NotNull final String text, @Nullable final PsiElement context) throws IncorrectOperationException { final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, EXPRESSION, level(context)), context); final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); if (!(element instanceof PsiExpression)) { @@ -353,7 +353,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ @NotNull @Override - public PsiTypeParameter createTypeParameterFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + public PsiTypeParameter createTypeParameterFromText(@NotNull final String text, @Nullable final PsiElement context) throws IncorrectOperationException { final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, TYPE_PARAMETER, level(context)), context); final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); if (!(element instanceof PsiTypeParameter)) { @@ -364,7 +364,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ @NotNull @Override - public PsiComment createCommentFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + public PsiComment createCommentFromText(@NotNull final String text, @Nullable final PsiElement context) throws IncorrectOperationException { final PsiJavaFile aFile = createDummyJavaFile(text); for (PsiElement aChildren : aFile.getChildren()) { if (aChildren instanceof PsiComment) { @@ -382,7 +382,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ @NotNull @Override - public PsiEnumConstant createEnumConstantFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + public PsiEnumConstant createEnumConstantFromText(@NotNull final String text, @Nullable final PsiElement context) throws IncorrectOperationException { final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, ENUM_CONSTANT, level(context)), context); final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); if (!(element instanceof PsiEnumConstant)) { @@ -393,8 +393,9 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ @NotNull @Override - public PsiCatchSection createCatchSection(@NotNull final PsiClassType exceptionType, @NotNull final String exceptionName, - final PsiElement context) throws IncorrectOperationException { + public PsiCatchSection createCatchSection(@NotNull final PsiClassType exceptionType, + @NotNull final String exceptionName, + @Nullable final PsiElement context) throws IncorrectOperationException { final String text = StringUtil .join("catch (", exceptionType.getCanonicalText(), " ", exceptionName, ") {}"); final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, CATCH_SECTION, level(context)), context); @@ -406,7 +407,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ return (PsiCatchSection)myManager.getCodeStyleManager().reformat(element); } - private void setupCatchBlock(final String exceptionName, final PsiElement context, final PsiCatchSection psiCatchSection) + private void setupCatchBlock(final String exceptionName, @Nullable final PsiElement context, final PsiCatchSection psiCatchSection) throws IncorrectOperationException { final FileTemplate catchBodyTemplate = FileTemplateManager.getInstance().getCodeTemplate(JavaTemplateUtil.TEMPLATE_CATCH_BODY); LOG.assertTrue(catchBodyTemplate != null); @@ -433,6 +434,7 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ psiCatchSection.getCatchBlock().replace(codeBlockFromText); } + @NotNull @Override public PsiType createPrimitiveType(@NotNull final String text, @NotNull final PsiAnnotation[] annotations) throws IncorrectOperationException { final PsiPrimitiveType primitiveType = getPrimitiveType(text); diff --git a/java/java-impl/src/com/intellij/psi/impl/file/JavaDirectoryServiceImpl.java b/java/java-impl/src/com/intellij/psi/impl/file/JavaDirectoryServiceImpl.java index e3d2e9b9975f..8b90ac321c85 100644 --- a/java/java-impl/src/com/intellij/psi/impl/file/JavaDirectoryServiceImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/file/JavaDirectoryServiceImpl.java @@ -62,7 +62,8 @@ public class JavaDirectoryServiceImpl extends JavaDirectoryService { List classes = null; for (PsiFile file : dir.getFiles()) { - if (file instanceof PsiClassOwner) { + FileViewProvider viewProvider = file.getViewProvider(); + if (file instanceof PsiClassOwner && file == viewProvider.getPsi(viewProvider.getBaseLanguage())) { PsiClass[] psiClasses = ((PsiClassOwner)file).getClasses(); if (psiClasses.length == 0) continue; if (classes == null) classes = new ArrayList(); diff --git a/java/java-impl/src/com/intellij/psi/util/proximity/KnownElementWeigher.java b/java/java-impl/src/com/intellij/psi/util/proximity/KnownElementWeigher.java index 7d510277860e..473735f376c9 100644 --- a/java/java-impl/src/com/intellij/psi/util/proximity/KnownElementWeigher.java +++ b/java/java-impl/src/com/intellij/psi/util/proximity/KnownElementWeigher.java @@ -32,6 +32,8 @@ public class KnownElementWeigher extends ProximityWeigher { if (element instanceof PsiClass) { @NonNls final String qname = ((PsiClass)element).getQualifiedName(); if (qname != null) { + if (qname.startsWith("java.lang")) return 4; + if (qname.startsWith("java.util")) return 3; if (qname.startsWith("java.")) return 2; if (qname.startsWith("javax.")) return 1; if (qname.startsWith("com.")) return -1; diff --git a/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceConstantPopup.java b/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceConstantPopup.java index 6fa66246a4aa..c1f9de00e9e8 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceConstantPopup.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceConstantPopup.java @@ -212,6 +212,7 @@ public class InplaceIntroduceConstantPopup { visibilityCombo.setRenderer(new ListCellRendererWrapper(visibilityCombo.getRenderer()) { @Override public void customize(JList list, String value, int index, boolean selected, boolean hasFocus) { + if (value == null) return; setText(PsiBundle.visibilityPresentation(value)); } }); @@ -283,7 +284,7 @@ public class InplaceIntroduceConstantPopup { renamer.performInplaceRename(false, nameSuggestions); } } - }, IntroduceConstantHandler.REFACTORING_NAME, null); + }, IntroduceConstantHandler.REFACTORING_NAME, IntroduceConstantHandler.REFACTORING_NAME); } private PsiField createFieldToStartTemplateOn(final String[] names, final PsiType psiType) { @@ -339,7 +340,8 @@ public class InplaceIntroduceConstantPopup { super(myProject, new TypeExpression(myProject, myTypeSelectorManager.getTypesForAll()), myEditor, field, false, myTypeSelectorManager.getTypesForAll().length > 1, - myExpr != null && myExpr.isPhysical() ? myEditor.getDocument().createRangeMarker(myExpr.getTextRange()) : null, InplaceIntroduceConstantPopup.this.getOccurrenceMarkers()); + myExpr != null && myExpr.isPhysical() ? myEditor.getDocument().createRangeMarker(myExpr.getTextRange()) : null, InplaceIntroduceConstantPopup.this.getOccurrenceMarkers(), + IntroduceConstantHandler.REFACTORING_NAME); myDefaultParameterTypePointer = SmartTypePointerManager.getInstance(myProject).createSmartTypePointer(myTypeSelectorManager.getDefaultType()); @@ -436,7 +438,7 @@ public class InplaceIntroduceConstantPopup { protected JComponent getComponent() { if (!myInitListeners) { myInitListeners = true; - final VisibilityListener visibilityListener = new VisibilityListener(myProject, myEditor) { + final VisibilityListener visibilityListener = new VisibilityListener(myProject, IntroduceConstantHandler.REFACTORING_NAME, myEditor) { @Override protected String getVisibility() { return getSelectedVisibility(); diff --git a/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceFieldPopup.java b/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceFieldPopup.java index 45cd42225d79..50ae57f05937 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceFieldPopup.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceFieldPopup.java @@ -176,7 +176,7 @@ public class InplaceIntroduceFieldPopup { renamer.performInplaceRename(false, nameSuggestions); } } - }, IntroduceFieldHandler.REFACTORING_NAME, null); + }, IntroduceFieldHandler.REFACTORING_NAME, IntroduceFieldHandler.REFACTORING_NAME); } private PsiField createFieldToStartTemplateOn(final String[] names, @@ -230,7 +230,8 @@ public class InplaceIntroduceFieldPopup { super(myProject, new TypeExpression(myProject, myTypeSelectorManager.getTypesForAll()), myEditor, psiVariable, false, myTypeSelectorManager.getTypesForAll().length > 1, - myInitializerExpression != null && myInitializerExpression.isPhysical() ? myEditor.getDocument().createRangeMarker(myInitializerExpression.getTextRange()) : null, InplaceIntroduceFieldPopup.this.getOccurrenceMarkers()); + myInitializerExpression != null && myInitializerExpression.isPhysical() ? myEditor.getDocument().createRangeMarker(myInitializerExpression.getTextRange()) : null, InplaceIntroduceFieldPopup.this.getOccurrenceMarkers(), + IntroduceFieldHandler.REFACTORING_NAME); myDefaultParameterTypePointer = SmartTypePointerManager.getInstance(myProject).createSmartTypePointer(myTypeSelectorManager.getDefaultType()); myFieldRangeStart = myEditor.getDocument().createRangeMarker(psiVariable.getTextRange()); @@ -276,13 +277,13 @@ public class InplaceIntroduceFieldPopup { protected JComponent getComponent() { if (!myInitListeners) { myInitListeners = true; - myIntroduceFieldPanel.addVisibilityListener(new VisibilityListener(myProject, myEditor){ + myIntroduceFieldPanel.addVisibilityListener(new VisibilityListener(myProject, IntroduceFieldHandler.REFACTORING_NAME, myEditor){ @Override protected String getVisibility() { return myIntroduceFieldPanel.getFieldVisibility(); } }); - final FinalListener finalListener = new FinalListener(myProject); + final FinalListener finalListener = new FinalListener(myProject, IntroduceFieldHandler.REFACTORING_NAME); myIntroduceFieldPanel.addFinalListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { diff --git a/java/java-impl/src/com/intellij/refactoring/introduceParameter/AbstractInplaceIntroducer.java b/java/java-impl/src/com/intellij/refactoring/introduceParameter/AbstractInplaceIntroducer.java index 6506cca2fb90..10d3d8886f3b 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceParameter/AbstractInplaceIntroducer.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceParameter/AbstractInplaceIntroducer.java @@ -57,8 +57,8 @@ public abstract class AbstractInplaceIntroducer extends VariableInplaceIntroduce boolean cantChangeFinalModifier, boolean hasTypeSuggestion, RangeMarker exprMarker, - List occurrenceMarkers) { - super(project, expression, editor, elementToRename, cantChangeFinalModifier, hasTypeSuggestion, exprMarker, occurrenceMarkers); + List occurrenceMarkers, String commandName) { + super(project, expression, editor, elementToRename, cantChangeFinalModifier, hasTypeSuggestion, exprMarker, occurrenceMarkers, commandName); } protected abstract boolean isReplaceAllOccurrences(); @@ -143,16 +143,18 @@ public abstract class AbstractInplaceIntroducer extends VariableInplaceIntroduce protected abstract class VisibilityListener implements ChangeListener { private Project myProject; + private final String myCommandName; private Editor myEditor; - protected VisibilityListener(Project project, Editor editor) { + protected VisibilityListener(Project project, String commandName, Editor editor) { myProject = project; + myCommandName = commandName; myEditor = editor; } @Override public void stateChanged(ChangeEvent e) { - new WriteCommandAction(myProject) { + new WriteCommandAction(myProject, myCommandName, myCommandName) { @Override protected void run(Result result) throws Throwable { final Document document = myEditor.getDocument(); diff --git a/java/java-impl/src/com/intellij/refactoring/introduceParameter/InplaceIntroduceParameterPopup.java b/java/java-impl/src/com/intellij/refactoring/introduceParameter/InplaceIntroduceParameterPopup.java index 2156d294d038..def824918107 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceParameter/InplaceIntroduceParameterPopup.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceParameter/InplaceIntroduceParameterPopup.java @@ -20,7 +20,9 @@ import com.intellij.codeInsight.template.impl.TemplateManagerImpl; import com.intellij.codeInsight.template.impl.TemplateState; import com.intellij.ide.ui.ListCellRendererWrapper; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.Result; import com.intellij.openapi.command.CommandProcessor; +import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.RangeMarker; import com.intellij.openapi.editor.ScrollType; @@ -202,7 +204,7 @@ class InplaceIntroduceParameterPopup extends IntroduceParameterSettingsUI { renamer.performInplaceRename(false, nameSuggestions); } } - }, IntroduceParameterHandler.REFACTORING_NAME, null); + }, IntroduceParameterHandler.REFACTORING_NAME, IntroduceParameterHandler.REFACTORING_NAME); } @Override @@ -234,7 +236,8 @@ class InplaceIntroduceParameterPopup extends IntroduceParameterSettingsUI { public ParameterInplaceIntroducer(PsiParameter parameter) { super(myProject, new TypeExpression(myProject, myTypeSelectorManager.getTypesForAll()), myEditor, parameter, myMustBeFinal, - myTypeSelectorManager.getTypesForAll().length > 1, myExprMarker, InplaceIntroduceParameterPopup.this.getOccurrenceMarkers()); + myTypeSelectorManager.getTypesForAll().length > 1, myExprMarker, InplaceIntroduceParameterPopup.this.getOccurrenceMarkers(), + IntroduceParameterHandler.REFACTORING_NAME); myDefaultParameterTypePointer = SmartTypePointerManager.getInstance(myProject).createSmartTypePointer(parameter.getType()); } diff --git a/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java b/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java index 784b3772ad1a..01c6be53da7d 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java @@ -478,7 +478,7 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase impleme final boolean cantChangeFinalModifier = hasWriteAccess || (inFinalContext && choice == OccurrencesChooser.ReplaceChoice.ALL); final VariableInplaceRenamer renamer = new VariableInplaceIntroducer(project, expression, editor, elementToRename, cantChangeFinalModifier, - typeSelectorManager.getTypesForAll().length > 1, exprMarker, occurrenceMarkers); + typeSelectorManager.getTypesForAll().length > 1, exprMarker, occurrenceMarkers, IntroduceVariableBase.REFACTORING_NAME); PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.getDocument()); renamer.performInplaceRename(false, new LinkedHashSet(Arrays.asList(suggestedName.names))); } diff --git a/java/java-impl/src/com/intellij/refactoring/introduceVariable/VariableInplaceIntroducer.java b/java/java-impl/src/com/intellij/refactoring/introduceVariable/VariableInplaceIntroducer.java index 50a4ca5a891f..9b584aaacde2 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceVariable/VariableInplaceIntroducer.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceVariable/VariableInplaceIntroducer.java @@ -38,7 +38,6 @@ import com.intellij.openapi.ui.popup.BalloonBuilder; import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.TextRange; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.JavaCodeStyleManager; @@ -52,7 +51,6 @@ import com.intellij.refactoring.ui.TypeSelectorManagerImpl; import com.intellij.ui.NonFocusableCheckBox; import com.intellij.ui.TitlePanel; import com.intellij.ui.awt.RelativePoint; -import com.intellij.util.ui.PositionTracker; import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -87,7 +85,8 @@ public class VariableInplaceIntroducer extends VariableInplaceRenamer { final boolean cantChangeFinalModifier, final boolean hasTypeSuggestion, final RangeMarker exprMarker, - final List occurrenceMarkers) { + final List occurrenceMarkers, + final String commandName) { super(elementToRename, editor); myProject = project; myEditor = editor; @@ -110,7 +109,7 @@ public class VariableInplaceIntroducer extends VariableInplaceRenamer { myCanBeFinal = new NonFocusableCheckBox("Declare final"); myCanBeFinal.setSelected(createFinals()); myCanBeFinal.setMnemonic('f'); - myCanBeFinal.addActionListener(new FinalListener(project)); + myCanBeFinal.addActionListener(new FinalListener(project, commandName)); } } @@ -381,9 +380,11 @@ public class VariableInplaceIntroducer extends VariableInplaceRenamer { public class FinalListener implements ActionListener { private final Project myProject; + private final String myCommandName; - public FinalListener(Project project) { + public FinalListener(Project project, String commandName) { myProject = project; + myCommandName = commandName; } @Override @@ -396,7 +397,7 @@ public class VariableInplaceIntroducer extends VariableInplaceRenamer { } public void perform(final boolean generateFinal, final String modifier) { - new WriteCommandAction(myProject){ + new WriteCommandAction(myProject, myCommandName, myCommandName){ @Override protected void run(com.intellij.openapi.application.Result result) throws Throwable { final Document document = myEditor.getDocument(); diff --git a/java/java-impl/src/com/intellij/refactoring/move/moveMembers/MoveJavaMemberHandler.java b/java/java-impl/src/com/intellij/refactoring/move/moveMembers/MoveJavaMemberHandler.java index 5f0ba5be7c99..41182af7d128 100644 --- a/java/java-impl/src/com/intellij/refactoring/move/moveMembers/MoveJavaMemberHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/move/moveMembers/MoveJavaMemberHandler.java @@ -16,16 +16,21 @@ package com.intellij.refactoring.move.moveMembers; import com.intellij.codeInsight.ChangeContextUtil; +import com.intellij.codeInsight.highlighting.ReadWriteAccessDetector; import com.intellij.psi.*; +import com.intellij.psi.impl.source.resolve.JavaResolveUtil; import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.searches.ReferencesSearch; +import com.intellij.psi.util.MethodSignatureUtil; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.PsiUtilBase; -import com.intellij.refactoring.util.EnumConstantsUtil; -import com.intellij.refactoring.util.RefactoringHierarchyUtil; -import com.intellij.refactoring.util.RefactoringUtil; +import com.intellij.refactoring.RefactoringBundle; +import com.intellij.refactoring.util.*; import com.intellij.util.IncorrectOperationException; import com.intellij.util.VisibilityUtil; +import com.intellij.util.containers.MultiMap; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; @@ -33,12 +38,13 @@ import java.util.*; /** * @author Maxim.Medvedev */ - public class MoveJavaMemberHandler implements MoveMemberHandler { - public MoveMembersProcessor.MoveMembersUsageInfo getUsage(PsiMember member, - PsiReference psiReference, - Set membersToMove, - PsiClass targetClass) { + @Override + @Nullable + public MoveMembersProcessor.MoveMembersUsageInfo getUsage(@NotNull PsiMember member, + @NotNull PsiReference psiReference, + @NotNull Set membersToMove, + @NotNull PsiClass targetClass) { PsiElement ref = psiReference.getElement(); if (ref instanceof PsiReferenceExpression) { PsiReferenceExpression refExpr = (PsiReferenceExpression)ref; @@ -70,15 +76,102 @@ public class MoveJavaMemberHandler implements MoveMemberHandler { return null; } - private static boolean isInMovedElement(PsiElement element, Set membersToMove) { + protected static boolean isInMovedElement(PsiElement element, Set membersToMove) { for (PsiMember member : membersToMove) { if (PsiTreeUtil.isAncestor(member, element, false)) return true; } return false; } - public boolean changeExternalUsage(MoveMembersOptions options, MoveMembersProcessor.MoveMembersUsageInfo usage) { - if (!usage.getElement().isValid()) return true; + @Override + public void checkConflictsOnUsage(@NotNull MoveMembersProcessor.MoveMembersUsageInfo usageInfo, + @Nullable String newVisibility, + @Nullable PsiModifierList modifierListCopy, + @NotNull PsiClass targetClass, + @NotNull Set membersToMove, + @NotNull MultiMap conflicts) { + final PsiElement element = usageInfo.getElement(); + if (element == null) return; + + final PsiMember member = usageInfo.member; + if (element instanceof PsiReferenceExpression) { + PsiExpression qualifier = ((PsiReferenceExpression)element).getQualifierExpression(); + PsiClass accessObjectClass = null; + if (qualifier != null) { + accessObjectClass = (PsiClass)PsiUtil.getAccessObjectClass(qualifier).getElement(); + } + + if (!JavaResolveUtil.isAccessible(member, targetClass, modifierListCopy, element, accessObjectClass, null)) { + String visibility = newVisibility != null ? newVisibility : VisibilityUtil.getVisibilityStringToDisplay(member); + String message = RefactoringBundle.message("0.with.1.visibility.is.not.accessible.from.2", + RefactoringUIUtil.getDescription(member, false), + visibility, + RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(element), true)); + conflicts.putValue(member, CommonRefactoringUtil.capitalize(message)); + } + } + + if (member instanceof PsiField && targetClass.isInterface()) { + ReadWriteAccessDetector accessDetector = ReadWriteAccessDetector.findDetector(member); + if (accessDetector != null) { + ReadWriteAccessDetector.Access access = accessDetector.getExpressionAccess(element); + if (access != ReadWriteAccessDetector.Access.Read) { + String message = RefactoringUIUtil.getDescription(member, true) + " has write access but is moved to an interface"; + conflicts.putValue(element, CommonRefactoringUtil.capitalize(message)); + } + } + } + + final PsiReference reference = usageInfo.getReference(); + if (reference != null) { + RefactoringConflictsUtil.checkAccessibilityConflicts(reference, member, modifierListCopy, targetClass, membersToMove, conflicts); + } + } + + @Override + public void checkConflictsOnMember(@NotNull PsiMember member, + @Nullable String newVisibility, + @Nullable PsiModifierList modifierListCopy, + @NotNull PsiClass targetClass, + @NotNull Set membersToMove, + @NotNull MultiMap conflicts) { + if (member instanceof PsiMethod && hasMethod(targetClass, (PsiMethod)member) || + member instanceof PsiField && hasField(targetClass, (PsiField)member)) { + String message = RefactoringBundle.message("0.already.exists.in.the.target.class", RefactoringUIUtil.getDescription(member, false)); + conflicts.putValue(member, CommonRefactoringUtil.capitalize(message)); + } + + RefactoringConflictsUtil.checkUsedElements(member, member, membersToMove, null, targetClass, targetClass, conflicts); + } + + protected static boolean hasMethod(PsiClass targetClass, PsiMethod method) { + PsiMethod[] targetClassMethods = targetClass.getMethods(); + for (PsiMethod candidate : targetClassMethods) { + if (candidate != method && + MethodSignatureUtil.areSignaturesEqual(method.getSignature(PsiSubstitutor.EMPTY), + candidate.getSignature(PsiSubstitutor.EMPTY))) { + return true; + } + } + return false; + } + + protected static boolean hasField(PsiClass targetClass, PsiField field) { + String fieldName = field.getName(); + PsiField[] targetClassFields = targetClass.getFields(); + for (PsiField candidate : targetClassFields) { + if (candidate != field && + fieldName.equals(candidate.getName())) { + return true; + } + } + return false; + } + + @Override + public boolean changeExternalUsage(@NotNull MoveMembersOptions options, @NotNull MoveMembersProcessor.MoveMembersUsageInfo usage) { + final PsiElement element = usage.getElement(); + if (element == null || !element.isValid()) return true; if (usage.reference instanceof PsiReferenceExpression) { PsiReferenceExpression refExpr = (PsiReferenceExpression)usage.reference; @@ -101,14 +194,24 @@ public class MoveJavaMemberHandler implements MoveMemberHandler { return false; } - public PsiMember doMove(MoveMembersOptions options, PsiMember member, PsiElement anchor, PsiClass targetClass) { + protected static void changeQualifier(PsiReferenceExpression refExpr, PsiClass aClass, PsiMember member) throws IncorrectOperationException { + if (RefactoringUtil.hasOnDemandStaticImport(refExpr, aClass)) { + refExpr.setQualifierExpression(null); + } + else if (!RefactoringUtil.hasStaticImportOn(refExpr, member)){ + PsiElementFactory factory = JavaPsiFacade.getInstance(refExpr.getProject()).getElementFactory(); + refExpr.setQualifierExpression(factory.createReferenceExpression(aClass)); + } + } + + @Override + @NotNull + public PsiMember doMove(@NotNull MoveMembersOptions options, @NotNull PsiMember member, PsiElement anchor, @NotNull PsiClass targetClass) { if (member instanceof PsiVariable) { ((PsiVariable)member).normalizeDeclaration(); } ChangeContextUtil.encodeContextInfo(member, true); - if (targetClass == null) return null; - final PsiMember memberCopy; if (options.makeEnumConstant() && @@ -118,8 +221,9 @@ public class MoveJavaMemberHandler implements MoveMemberHandler { } else { memberCopy = (PsiMember)member.copy(); - if (member.getContainingClass().isInterface() && !targetClass.isInterface()) { - //might need to make modifiers explicit, see IDEADEV-11416 + final PsiClass containingClass = member.getContainingClass(); + if (containingClass != null && containingClass.isInterface() && !targetClass.isInterface()) { + // might need to make modifiers explicit, see IDEADEV-11416 final PsiModifierList list = memberCopy.getModifierList(); assert list != null; list.setModifierProperty(PsiModifier.STATIC, member.hasModifierProperty(PsiModifier.STATIC)); @@ -131,22 +235,14 @@ public class MoveJavaMemberHandler implements MoveMemberHandler { return anchor != null ? (PsiMember)targetClass.addAfter(memberCopy, anchor) : (PsiMember)targetClass.add(memberCopy); } - public void decodeContextInfo(PsiElement scope) { + @Override + public void decodeContextInfo(@NotNull PsiElement scope) { ChangeContextUtil.decodeContextInfo(scope, null, null); } - private static void changeQualifier(PsiReferenceExpression refExpr, PsiClass aClass, PsiMember member) throws IncorrectOperationException { - if (RefactoringUtil.hasOnDemandStaticImport(refExpr, aClass)) { - refExpr.setQualifierExpression(null); - } - else if (!RefactoringUtil.hasStaticImportOn(refExpr, member)){ - PsiElementFactory factory = JavaPsiFacade.getInstance(refExpr.getProject()).getElementFactory(); - refExpr.setQualifierExpression(factory.createReferenceExpression(aClass)); - } - } - + @Override @Nullable - public PsiElement getAnchor(final PsiMember member, final PsiClass targetClass) { + public PsiElement getAnchor(@NotNull final PsiMember member, @NotNull final PsiClass targetClass) { if (member instanceof PsiField && member.hasModifierProperty(PsiModifier.STATIC)) { final List afterFields = new ArrayList(); final PsiExpression psiExpression = ((PsiField)member).getInitializer(); diff --git a/java/java-impl/src/com/intellij/refactoring/move/moveMembers/MoveMemberHandler.java b/java/java-impl/src/com/intellij/refactoring/move/moveMembers/MoveMemberHandler.java index 0200f83e5194..ce028217ec3e 100644 --- a/java/java-impl/src/com/intellij/refactoring/move/moveMembers/MoveMemberHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/move/moveMembers/MoveMemberHandler.java @@ -16,10 +16,9 @@ package com.intellij.refactoring.move.moveMembers; import com.intellij.lang.LanguageExtension; -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiMember; -import com.intellij.psi.PsiReference; +import com.intellij.psi.*; +import com.intellij.util.containers.MultiMap; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Set; @@ -30,17 +29,36 @@ import java.util.Set; public interface MoveMemberHandler { LanguageExtension EP_NAME = new LanguageExtension("com.intellij.refactoring.moveMemberHandler"); - MoveMembersProcessor.MoveMembersUsageInfo getUsage(PsiMember member, - PsiReference ref, - Set membersToMove, - PsiClass targetClass); + @Nullable + MoveMembersProcessor.MoveMembersUsageInfo getUsage(@NotNull PsiMember member, + @NotNull PsiReference ref, + @NotNull Set membersToMove, + @NotNull PsiClass targetClass); - boolean changeExternalUsage(MoveMembersOptions options, MoveMembersProcessor.MoveMembersUsageInfo usage); + void checkConflictsOnUsage(@NotNull MoveMembersProcessor.MoveMembersUsageInfo usageInfo, + @Nullable String newVisibility, + @Nullable PsiModifierList modifierListCopy, + @NotNull PsiClass targetClass, + @NotNull Set membersToMove, + @NotNull MultiMap conflicts); - PsiMember doMove(MoveMembersOptions options, PsiMember member, PsiElement anchor, PsiClass targetClass); - - void decodeContextInfo(PsiElement scope); + void checkConflictsOnMember(@NotNull PsiMember member, + @Nullable String newVisibility, + @Nullable PsiModifierList modifierListCopy, + @NotNull PsiClass targetClass, + @NotNull Set membersToMove, + @NotNull MultiMap conflicts); @Nullable - PsiElement getAnchor(PsiMember member, PsiClass targetClass); + PsiElement getAnchor(@NotNull PsiMember member, @NotNull PsiClass targetClass); + + boolean changeExternalUsage(@NotNull MoveMembersOptions options, @NotNull MoveMembersProcessor.MoveMembersUsageInfo usage); + + @NotNull + PsiMember doMove(@NotNull MoveMembersOptions options, + @NotNull PsiMember member, + @Nullable PsiElement anchor, + @NotNull PsiClass targetClass); + + void decodeContextInfo(@NotNull PsiElement scope); } diff --git a/java/java-impl/src/com/intellij/refactoring/move/moveMembers/MoveMembersProcessor.java b/java/java-impl/src/com/intellij/refactoring/move/moveMembers/MoveMembersProcessor.java index 5560118bd8f2..6dfaa8e2c303 100644 --- a/java/java-impl/src/com/intellij/refactoring/move/moveMembers/MoveMembersProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/move/moveMembers/MoveMembersProcessor.java @@ -15,17 +15,13 @@ */ package com.intellij.refactoring.move.moveMembers; -import com.intellij.codeInsight.highlighting.ReadWriteAccessDetector; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Ref; import com.intellij.psi.*; -import com.intellij.psi.impl.source.resolve.JavaResolveUtil; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.searches.ReferencesSearch; -import com.intellij.psi.util.MethodSignatureUtil; import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.PsiUtilBase; import com.intellij.refactoring.BaseRefactoringProcessor; import com.intellij.refactoring.HelpID; @@ -34,7 +30,9 @@ import com.intellij.refactoring.listeners.RefactoringElementListener; import com.intellij.refactoring.move.MoveCallback; import com.intellij.refactoring.move.MoveHandler; import com.intellij.refactoring.move.MoveMemberViewDescriptor; -import com.intellij.refactoring.util.*; +import com.intellij.refactoring.util.CommonRefactoringUtil; +import com.intellij.refactoring.util.MoveRenameUsageInfo; +import com.intellij.refactoring.util.RefactoringConflictsUtil; import com.intellij.usageView.UsageInfo; import com.intellij.usageView.UsageViewDescriptor; import com.intellij.usageView.UsageViewUtil; @@ -44,6 +42,7 @@ import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashMap; import com.intellij.util.containers.MultiMap; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.*; @@ -61,16 +60,16 @@ public class MoveMembersProcessor extends BaseRefactoringProcessor { private String myCommandName = MoveMembersImpl.REFACTORING_NAME; private MoveMembersOptions myOptions; - public MoveMembersProcessor(Project project, MoveCallback moveCallback, MoveMembersOptions options) { + public MoveMembersProcessor(Project project, MoveMembersOptions options) { + this(project, null, options); + } + + public MoveMembersProcessor(Project project, @Nullable MoveCallback moveCallback, MoveMembersOptions options) { super(project); myMoveCallback = moveCallback; setOptions(options); } - public MoveMembersProcessor(Project project, MoveMembersOptions options) { - this(project, null, options); - } - protected String getCommandName() { return myCommandName; } @@ -152,10 +151,11 @@ public class MoveMembersProcessor extends BaseRefactoringProcessor { protected void performRefactoring(final UsageInfo[] usages) { try { - // correct references to moved members from the outside PsiClass targetClass = JavaPsiFacade.getInstance(myProject).findClass(myOptions.getTargetClassName(), GlobalSearchScope.projectScope(myProject)); if (targetClass == null) return; + + // collect anchors to place moved members at final Map anchors = new HashMap(); for (PsiMember member : myMembersToMove) { final MoveMemberHandler handler = MoveMemberHandler.EP_NAME.forLanguage(member.getLanguage()); @@ -163,12 +163,14 @@ public class MoveMembersProcessor extends BaseRefactoringProcessor { anchors.put(member, handler.getAnchor(member, targetClass)); } } + + // correct references to moved members from the outside ArrayList otherUsages = new ArrayList(); for (UsageInfo usageInfo : usages) { MoveMembersUsageInfo usage = (MoveMembersUsageInfo)usageInfo; if (!usage.reference.isValid()) continue; final MoveMemberHandler handler = MoveMemberHandler.EP_NAME.forLanguage(usageInfo.getElement().getLanguage()); - if (handler!=null) { + if (handler != null) { if (handler.changeExternalUsage(myOptions, usage)) continue; } otherUsages.add(usage); @@ -190,7 +192,7 @@ public class MoveMembersProcessor extends BaseRefactoringProcessor { final RefactoringElementListener elementListener = getTransaction().getElementListener(member); final MoveMemberHandler handler = MoveMemberHandler.EP_NAME.forLanguage(member.getLanguage()); if (handler != null) { - PsiMember newMember=handler.doMove(myOptions, member, anchors.get(member), targetClass); + PsiMember newMember = handler.doMove(myOptions, member, anchors.get(member), targetClass); elementListener.elementMoved(newMember); fixModifierList(newMember, usages); @@ -201,7 +203,6 @@ public class MoveMembersProcessor extends BaseRefactoringProcessor { } // qualifier info must be decoded after members are moved - //ChangeContextUtil.decodeContextInfo(myTargetClass, null, null); final MoveMemberHandler handler = MoveMemberHandler.EP_NAME.forLanguage(myTargetClass.getLanguage()); if (handler != null) handler.decodeContextInfo(myTargetClass); @@ -236,65 +237,63 @@ public class MoveMembersProcessor extends BaseRefactoringProcessor { protected boolean preprocessUsages(Ref refUsages) { final MultiMap conflicts = new MultiMap(); final UsageInfo[] usages = refUsages.get(); - try { - addInaccessibleConflicts(conflicts, usages); - } - catch (IncorrectOperationException e) { - LOG.error(e); - } - analyzeMoveConflicts(myMembersToMove, myTargetClass, myNewVisibility, conflicts); - RefactoringConflictsUtil.analyzeModuleConflicts(myProject, myMembersToMove, usages, myTargetClass, conflicts); - return showConflicts(conflicts, usages); - } - private void addInaccessibleConflicts(final MultiMap conflicts, final UsageInfo[] usages) throws IncorrectOperationException { String newVisibility = myNewVisibility; - if (VisibilityUtil.ESCALATE_VISIBILITY.equals(newVisibility)) { //Still need to check for access object + if (VisibilityUtil.ESCALATE_VISIBILITY.equals(newVisibility)) { // still need to check for access object newVisibility = PsiModifier.PUBLIC; } - Map modifierListCopies = new HashMap(); + final Map modifierListCopies = new HashMap(); for (PsiMember member : myMembersToMove) { - PsiModifierList copy = member.getModifierList(); - if (copy != null) copy = (PsiModifierList)copy.copy(); - if (newVisibility != null) { - if (copy != null) VisibilityUtil.setVisibility(copy, newVisibility); + PsiModifierList modifierListCopy = member.getModifierList(); + if (modifierListCopy != null) { + modifierListCopy = (PsiModifierList)modifierListCopy.copy(); } - modifierListCopies.put(member, copy); + if (modifierListCopy != null && newVisibility != null) { + try { + VisibilityUtil.setVisibility(modifierListCopy, newVisibility); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + } + modifierListCopies.put(member, modifierListCopy); } + analyzeConflictsOnUsages(usages, myMembersToMove, newVisibility, myTargetClass, modifierListCopies, conflicts); + analyzeConflictsOnMembers(myMembersToMove, newVisibility, myTargetClass, modifierListCopies, conflicts); + + RefactoringConflictsUtil.analyzeModuleConflicts(myProject, myMembersToMove, usages, myTargetClass, conflicts); + + return showConflicts(conflicts, usages); + } + + private static void analyzeConflictsOnUsages(UsageInfo[] usages, + Set membersToMove, + String newVisibility, + PsiClass targetClass, + Map modifierListCopies, + MultiMap conflicts) { for (UsageInfo usage : usages) { - if (usage instanceof MoveMembersUsageInfo) { - final MoveMembersUsageInfo usageInfo = (MoveMembersUsageInfo)usage; - PsiElement element = usage.getElement(); - if (element != null) { - final PsiMember member = usageInfo.member; - if (element instanceof PsiReferenceExpression) { - PsiExpression qualifier = ((PsiReferenceExpression)element).getQualifierExpression(); - PsiClass accessObjectClass = null; - if (qualifier != null) { - accessObjectClass = (PsiClass)PsiUtil.getAccessObjectClass(qualifier).getElement(); - } + if (!(usage instanceof MoveMembersUsageInfo)) continue; + final MoveMembersUsageInfo usageInfo = (MoveMembersUsageInfo)usage; + final PsiMember member = usageInfo.member; + final MoveMemberHandler handler = MoveMemberHandler.EP_NAME.forLanguage(member.getLanguage()); + if (handler != null) { + handler.checkConflictsOnUsage(usageInfo, newVisibility, modifierListCopies.get(member), targetClass, membersToMove, conflicts); + } + } + } - if (!JavaResolveUtil.isAccessible(member, myTargetClass, modifierListCopies.get(member), element, accessObjectClass, null)) { - newVisibility = newVisibility == null ? VisibilityUtil.getVisibilityStringToDisplay(member) : newVisibility; - String message = - CommonRefactoringUtil.capitalize(RefactoringBundle.message("0.with.1.visibility.is.not.accessible.from.2", RefactoringUIUtil.getDescription(member, false), - newVisibility, RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(element), true))); - conflicts.putValue(member, message); - } - } - - if (member instanceof PsiField && myTargetClass.isInterface()) { - final ReadWriteAccessDetector accessDetector = ReadWriteAccessDetector.findDetector(member); - if (accessDetector != null) { - final ReadWriteAccessDetector.Access access = accessDetector.getExpressionAccess(element); - if (access != ReadWriteAccessDetector.Access.Read) { - conflicts.putValue(element, CommonRefactoringUtil.capitalize(RefactoringUIUtil.getDescription(member, true)) + " has write access but is moved to an interface"); - } - } - } - } + private static void analyzeConflictsOnMembers(Set membersToMove, + String newVisibility, + PsiClass targetClass, + Map modifierListCopies, + MultiMap conflicts) { + for (final PsiMember member : membersToMove) { + final MoveMemberHandler handler = MoveMemberHandler.EP_NAME.forLanguage(member.getLanguage()); + if (handler != null) { + handler.checkConflictsOnMember(member, newVisibility, modifierListCopies.get(member), targetClass, membersToMove, conflicts); } } } @@ -308,53 +307,6 @@ public class MoveMembersProcessor extends BaseRefactoringProcessor { super.doRun(); } - private static void analyzeMoveConflicts(@NotNull Set membersToMove, final PsiClass targetClass, final String newVisibility, - MultiMap conflicts) { - for (final PsiMember member : membersToMove) { - if (member instanceof PsiMethod) { - PsiMethod method = (PsiMethod)member; - if (hasMethod(targetClass, method)) { - String message = RefactoringBundle.message("0.already.exists.in.the.target.class", RefactoringUIUtil.getDescription(method, false)); - message = CommonRefactoringUtil.capitalize(message); - conflicts.putValue(method, message); - } - } - else if (member instanceof PsiField) { - PsiField field = (PsiField)member; - if (hasField(targetClass, field)) { - String message = RefactoringBundle.message("0.already.exists.in.the.target.class", RefactoringUIUtil.getDescription(field, false)); - message = CommonRefactoringUtil.capitalize(message); - conflicts.putValue(field, message); - } - } - } - RefactoringConflictsUtil.analyzeAccessibilityConflicts(membersToMove, targetClass, conflicts, newVisibility); - } - - private static boolean hasMethod(PsiClass targetClass, PsiMethod method) { - PsiMethod[] targetClassMethods = targetClass.getMethods(); - for (PsiMethod candidate : targetClassMethods) { - if (candidate != method && - MethodSignatureUtil.areSignaturesEqual(method.getSignature(PsiSubstitutor.EMPTY), - candidate.getSignature(PsiSubstitutor.EMPTY))) { - return true; - } - } - return false; - } - - private static boolean hasField(PsiClass targetClass, PsiField field) { - String fieldName = field.getName(); - PsiField[] targetClassFields = targetClass.getFields(); - for (PsiField candidate : targetClassFields) { - if (candidate != field && - fieldName.equals(candidate.getName())) { - return true; - } - } - return false; - } - public List getMembers() { return new ArrayList(myMembersToMove); } diff --git a/java/java-impl/src/com/intellij/refactoring/util/RefactoringConflictsUtil.java b/java/java-impl/src/com/intellij/refactoring/util/RefactoringConflictsUtil.java index e8b6538af7cd..53b4e9aea17c 100644 --- a/java/java-impl/src/com/intellij/refactoring/util/RefactoringConflictsUtil.java +++ b/java/java-impl/src/com/intellij/refactoring/util/RefactoringConflictsUtil.java @@ -48,13 +48,16 @@ public class RefactoringConflictsUtil { private RefactoringConflictsUtil() { } public static void analyzeAccessibilityConflicts(@NotNull Set membersToMove, - @NotNull final PsiClass targetClass, - final MultiMap conflicts, String newVisibility) { + @NotNull PsiClass targetClass, + @NotNull MultiMap conflicts, + @Nullable String newVisibility) { analyzeAccessibilityConflicts(membersToMove, targetClass, conflicts, newVisibility, targetClass, null); } - public static void analyzeAccessibilityConflicts(@NotNull Set membersToMove, @Nullable final PsiClass targetClass, final MultiMap conflicts, - String newVisibility, + public static void analyzeAccessibilityConflicts(@NotNull Set membersToMove, + @Nullable PsiClass targetClass, + @NotNull MultiMap conflicts, + @Nullable String newVisibility, @NotNull PsiElement context, @Nullable Set abstractMethods) { if (VisibilityUtil.ESCALATE_VISIBILITY.equals(newVisibility)) { //Still need to check for access object @@ -63,41 +66,65 @@ public class RefactoringConflictsUtil { for (PsiMember member : membersToMove) { checkUsedElements(member, member, membersToMove, abstractMethods, targetClass, context, conflicts); + checkAccessibilityConflicts(member, newVisibility, targetClass, membersToMove, conflicts); + } + } - PsiModifierList modifierList = member.getModifierList(); - if (modifierList != null) modifierList = (PsiModifierList)modifierList.copy(); - - if (newVisibility != null) { - try { - if (modifierList != null) VisibilityUtil.setVisibility(modifierList, newVisibility); - } - catch (IncorrectOperationException ex) { - /* do nothing and hope for the best */ - } + public static void checkAccessibilityConflicts(@NotNull PsiMember member, + @Nullable String newVisibility, + @Nullable PsiClass targetClass, + @NotNull Set membersToMove, + @NotNull MultiMap conflicts) { + PsiModifierList modifierListCopy = member.getModifierList(); + if (modifierListCopy != null) { + modifierListCopy = (PsiModifierList)modifierListCopy.copy(); + } + if (newVisibility != null && modifierListCopy != null) { + try { + VisibilityUtil.setVisibility(modifierListCopy, newVisibility); } - JavaPsiFacade manager = JavaPsiFacade.getInstance(member.getProject()); - for (PsiReference psiReference : ReferencesSearch.search(member)) { - PsiElement ref = psiReference.getElement(); - if (!RefactoringHierarchyUtil.willBeInTargetClass(ref, membersToMove, targetClass, false)) { - //Check for target class accessibility - if (targetClass != null && !manager.getResolveHelper().isAccessible(targetClass, targetClass.getModifierList(), ref, null, null)) { - String message = RefactoringBundle.message("0.is.1.and.will.not.be.accessible.from.2.in.the.target.class", - RefactoringUIUtil.getDescription(targetClass, true), - VisibilityUtil.getVisibilityStringToDisplay(targetClass), - RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(ref), true)); - message = CommonRefactoringUtil.capitalize(message); - conflicts.putValue(targetClass, message); - } - //check for member accessibility - else if (!manager.getResolveHelper().isAccessible(member, modifierList, ref, null, null)) { - String message = RefactoringBundle.message("0.is.1.and.will.not.be.accessible.from.2.in.the.target.class", - RefactoringUIUtil.getDescription(member, true), - VisibilityUtil.getVisibilityStringToDisplay(member), - RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(ref), true)); - message = CommonRefactoringUtil.capitalize(message); - conflicts.putValue(member, message); - } - } + catch (IncorrectOperationException ignore) { } // do nothing and hope for the best + } + + checkAccessibilityConflicts(member, modifierListCopy, targetClass, membersToMove, conflicts); + } + + public static void checkAccessibilityConflicts(@NotNull PsiMember member, + @Nullable PsiModifierList modifierListCopy, + @Nullable PsiClass targetClass, + @NotNull Set membersToMove, + @NotNull MultiMap conflicts) { + for (PsiReference psiReference : ReferencesSearch.search(member)) { + checkAccessibilityConflicts(psiReference, member, modifierListCopy, targetClass, membersToMove, conflicts); + } + } + + public static void checkAccessibilityConflicts(@NotNull PsiReference reference, + @NotNull PsiMember member, + @Nullable PsiModifierList modifierListCopy, + @Nullable PsiClass targetClass, + @NotNull Set membersToMove, + @NotNull MultiMap conflicts) { + JavaPsiFacade manager = JavaPsiFacade.getInstance(member.getProject()); + PsiElement ref = reference.getElement(); + if (!RefactoringHierarchyUtil.willBeInTargetClass(ref, membersToMove, targetClass, false)) { + // check for target class accessibility + if (targetClass != null && !manager.getResolveHelper().isAccessible(targetClass, targetClass.getModifierList(), ref, null, null)) { + String message = RefactoringBundle.message("0.is.1.and.will.not.be.accessible.from.2.in.the.target.class", + RefactoringUIUtil.getDescription(targetClass, true), + VisibilityUtil.getVisibilityStringToDisplay(targetClass), + RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(ref), true)); + message = CommonRefactoringUtil.capitalize(message); + conflicts.putValue(targetClass, message); + } + // check for member accessibility + else if (!manager.getResolveHelper().isAccessible(member, modifierListCopy, ref, null, null)) { + String message = RefactoringBundle.message("0.is.1.and.will.not.be.accessible.from.2.in.the.target.class", + RefactoringUIUtil.getDescription(member, true), + VisibilityUtil.getVisibilityStringToDisplay(member), + RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(ref), true)); + message = CommonRefactoringUtil.capitalize(message); + conflicts.putValue(member, message); } } } @@ -155,7 +182,7 @@ public class RefactoringConflictsUtil { public static void checkAccessibility(PsiMember refMember, @NotNull PsiElement newContext, - PsiClass accessClass, + @Nullable PsiClass accessClass, PsiMember member, MultiMap conflicts) { if (!PsiUtil.isAccessible(refMember, newContext, accessClass)) { @@ -176,24 +203,24 @@ public class RefactoringConflictsUtil { } } - public static void analyzeModuleConflicts(Project project, - Collection scope, + public static void analyzeModuleConflicts(final Project project, + final Collection scopes, final UsageInfo[] usages, - PsiElement target, + final PsiElement target, final MultiMap conflicts) { - if (scope == null) return; + if (scopes == null) return; final VirtualFile vFile = PsiUtilBase.getVirtualFile(target); if (vFile == null) return; - analyzeModuleConflicts(project, scope, usages, vFile, conflicts); + + analyzeModuleConflicts(project, scopes, usages, vFile, conflicts); } - public static void analyzeModuleConflicts(Project project, + public static void analyzeModuleConflicts(final Project project, final Collection scopes, final UsageInfo[] usages, final VirtualFile vFile, final MultiMap conflicts) { if (scopes == null) return; - for (final PsiElement scope : scopes) { if (scope instanceof PsiPackage || scope instanceof PsiDirectory) return; } @@ -207,16 +234,16 @@ public class RefactoringConflictsUtil { @Override public void visitReferenceElement(PsiJavaCodeReferenceElement reference) { super.visitReferenceElement(reference); final PsiElement resolved = reference.resolve(); - if (resolved != null && !reported.contains(resolved) && !CommonRefactoringUtil.isAncestor(resolved, scopes) && + if (resolved != null && + !reported.contains(resolved) && + !CommonRefactoringUtil.isAncestor(resolved, scopes) && !PsiSearchScopeUtil.isInScope(resolveScope, resolved)) { - final String scopeDescription = - RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(reference), true); + final String scopeDescription = RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(reference), true); final String message = RefactoringBundle.message("0.referenced.in.1.will.not.be.accessible.in.module.2", - CommonRefactoringUtil.capitalize( - RefactoringUIUtil.getDescription(resolved, true)), scopeDescription, - CommonRefactoringUtil.htmlEmphasize( - targetModule.getName())); - conflicts.putValue(resolved, message); + RefactoringUIUtil.getDescription(resolved, true), + scopeDescription, + CommonRefactoringUtil.htmlEmphasize(targetModule.getName())); + conflicts.putValue(resolved, CommonRefactoringUtil.capitalize(message)); reported.add(resolved); } } @@ -255,19 +282,17 @@ public class RefactoringConflictsUtil { assert referencedElement != null : moveRenameUsageInfo; if (module == targetModule && isInTestSources) { message = RefactoringBundle.message("0.referenced.in.1.will.not.be.accessible.from.production.of.module.2", - CommonRefactoringUtil.capitalize( - RefactoringUIUtil.getDescription(referencedElement, true)), + RefactoringUIUtil.getDescription(referencedElement, true), scopeDescription, CommonRefactoringUtil.htmlEmphasize(module.getName())); } else { message = RefactoringBundle.message("0.referenced.in.1.will.not.be.accessible.from.module.2", - CommonRefactoringUtil.capitalize( - RefactoringUIUtil.getDescription(referencedElement, true)), + RefactoringUIUtil.getDescription(referencedElement, true), scopeDescription, CommonRefactoringUtil.htmlEmphasize(module.getName())); } - conflicts.putValue(referencedElement, message); + conflicts.putValue(referencedElement, CommonRefactoringUtil.capitalize(message)); } } } @@ -275,4 +300,4 @@ public class RefactoringConflictsUtil { } } } -} \ No newline at end of file +} diff --git a/java/java-tests/testData/codeInsight/completeStatement/MultilineReturn.java b/java/java-tests/testData/codeInsight/completeStatement/MultilineReturn.java new file mode 100644 index 000000000000..29fb958d20a5 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completeStatement/MultilineReturn.java @@ -0,0 +1,6 @@ +class Test { + Object method() { + return + null + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completeStatement/MultilineReturn_after.java b/java/java-tests/testData/codeInsight/completeStatement/MultilineReturn_after.java new file mode 100644 index 000000000000..7dcbe27e45fa --- /dev/null +++ b/java/java-tests/testData/codeInsight/completeStatement/MultilineReturn_after.java @@ -0,0 +1,6 @@ +class Test { + Object method() { + return + null; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/smartType/NoWrongSubstitutorFromStats-out.java b/java/java-tests/testData/codeInsight/completion/smartType/NoWrongSubstitutorFromStats-out.java new file mode 100644 index 000000000000..4f68901ba4b6 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/NoWrongSubstitutorFromStats-out.java @@ -0,0 +1,16 @@ +import java.util.Comparator; +import java.util.List; +import java.util.Collections; + +public class Foo { + private List myList; + + private void sort() { + Collections.sort(myList, new Comparator() { + @Override + public int compare(String o1, String o2) { + return 0; //To change body of implemented methods use File | Settings | File Templates. + } + }); + } +} diff --git a/java/java-tests/testData/codeInsight/completion/smartType/NoWrongSubstitutorFromStats.java b/java/java-tests/testData/codeInsight/completion/smartType/NoWrongSubstitutorFromStats.java new file mode 100644 index 000000000000..0e4c7a811db3 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/NoWrongSubstitutorFromStats.java @@ -0,0 +1,10 @@ +import java.util.List; +import java.util.Collections; + +public class Foo { + private List myList; + + private void sort() { + Collections.sort(myList, new Comparator); + } +} diff --git a/java/java-tests/testData/codeInsight/completion/word/InJavaLiterals.java b/java/java-tests/testData/codeInsight/completion/word/InJavaLiterals.java new file mode 100644 index 000000000000..49bce3236819 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/word/InJavaLiterals.java @@ -0,0 +1,3 @@ +public class MyClass { + String b = "My"; +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/word/InJavaLiterals_after.java b/java/java-tests/testData/codeInsight/completion/word/InJavaLiterals_after.java new file mode 100644 index 000000000000..5a3075cdc74e --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/word/InJavaLiterals_after.java @@ -0,0 +1,3 @@ +public class MyClass { + String b = "MyClass"; +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/CompleteStatementTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/CompleteStatementTest.java index 5ccafe430ead..8e6711825467 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/CompleteStatementTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/CompleteStatementTest.java @@ -5,7 +5,6 @@ import com.intellij.openapi.actionSystem.IdeActions; import com.intellij.openapi.roots.LanguageLevelProjectExtension; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.JavaPsiFacade; -import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.testFramework.EditorActionTestCase; @@ -185,6 +184,8 @@ public class CompleteStatementTest extends EditorActionTestCase { public void testIDEADEV40479() throws Exception { doTest(); } + public void testMultilineReturn() throws Exception { doTest(); } + public void testIDEADEV13019() throws Exception { doTestBracesNextLineStyle(); } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy index 22d144e12c6e..e910b3a75524 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy @@ -19,6 +19,8 @@ import com.intellij.codeInsight.completion.impl.CompletionServiceImpl import com.intellij.codeInsight.lookup.Lookup import com.intellij.codeInsight.lookup.LookupManager import com.intellij.codeInsight.lookup.impl.LookupImpl +import com.intellij.codeInsight.template.TemplateManager +import com.intellij.codeInsight.template.impl.TemplateManagerImpl import com.intellij.ide.DataManager import com.intellij.ide.ui.UISettings import com.intellij.openapi.actionSystem.IdeActions @@ -690,4 +692,36 @@ class Foo { assert myFixture.editor.document.text.contains('foo(aaa,)') } + public void testCompletionWhenLiveTemplateAreNotSufficient() { + ((TemplateManagerImpl)TemplateManager.getInstance(getProject())).setTemplateTesting(true); + try { + myFixture.configureByText("a.java", """ + class Foo { + { + Iterable l1 = null; + Iterable l2 = null; + Object asdf = null; + iter + } + } + """) + type '\t' + assert myFixture.lookupElementStrings == ['l2', 'l1'] + type 'as' + assert lookup + assert myFixture.lookupElementStrings == ['asdf', 'assert'] + } + finally { + ((TemplateManagerImpl)TemplateManager.getInstance(getProject())).setTemplateTesting(false); + } + + } + + public void testNoWordCompletionAutoPopup() { + myFixture.configureByText "a.java", 'class Bar { void foo() { "f" }}' + type 'o' + assert !lookup + } + + } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java index 9e77c2091a63..08cd420d3ae2 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java @@ -11,6 +11,7 @@ import com.intellij.codeInsight.template.TemplateContextType; import com.intellij.codeInsight.template.TemplateManager; import com.intellij.codeInsight.template.impl.TemplateImpl; import com.intellij.codeInsight.template.impl.TemplateSettings; +import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.util.Condition; import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; @@ -984,6 +985,12 @@ public class SmartTypeCompletionTest extends LightFixtureCompletionTestCase { assertStringItems("Bar", "Goo"); } + public void testNoWrongSubstitutorFromStats() throws Throwable { + doTest(); + FileDocumentManager.getInstance().saveDocument(myFixture.getEditor().getDocument()); + doTest(); // stats are changed now + } + public void testCommonPrefixWithSelection() throws Throwable { doItemTest(); } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/WordCompletionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/WordCompletionTest.java index af12e034f247..e244c329f92f 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/WordCompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/WordCompletionTest.java @@ -40,17 +40,12 @@ public class WordCompletionTest extends CompletionTestCase { @Override @NotNull public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull final ProcessingContext context) { - return new PsiReference[]{new PsiReferenceBase(element) { + return new PsiReference[]{new PsiReferenceBase(element, true) { @Override public PsiElement resolve() { return null; } - @Override - public boolean isSoft() { - return true; - } - @Override @NotNull public Object[] getVariants() { @@ -63,17 +58,12 @@ public class WordCompletionTest extends CompletionTestCase { @Override @NotNull public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull final ProcessingContext context) { - return new PsiReference[]{new PsiReferenceBase(element) { + return new PsiReference[]{new PsiReferenceBase(element, false) { @Override public PsiElement resolve() { return null; } - @Override - public boolean isSoft() { - return false; - } - @Override @NotNull public Object[] getVariants() { @@ -89,6 +79,11 @@ public class WordCompletionTest extends CompletionTestCase { checkResultByFile(BASE_PATH + "3_after.java"); } + public void testInJavaLiterals() throws Exception { + configureByFile(BASE_PATH + "InJavaLiterals.java"); + checkResultByFile(BASE_PATH + "InJavaLiterals_after.java"); + } + public void testComments() throws Throwable { configureByFile(BASE_PATH + "4.java"); checkResultByFile(BASE_PATH + "4_after.java"); diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/AnnotateMethodTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/AnnotateMethodTest.java index 23fbfa6298d5..59683ae56fcc 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/AnnotateMethodTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/AnnotateMethodTest.java @@ -1,9 +1,10 @@ package com.intellij.codeInsight.daemon.quickFix; +import com.intellij.codeInspection.AnnotateMethodFix; import com.intellij.codeInspection.LocalInspectionTool; import com.intellij.codeInspection.nullable.NullableStuffInspection; -import com.intellij.psi.PsiMethod; import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiMethod; import org.jetbrains.annotations.NonNls; public class AnnotateMethodTest extends LightQuickFix15TestCase { @@ -18,14 +19,20 @@ public class AnnotateMethodTest extends LightQuickFix15TestCase { protected LocalInspectionTool[] configureLocalInspectionTools() { return new LocalInspectionTool[]{new NullableStuffInspection(){ @Override - protected int annotateBaseMethod(final PsiMethod method, final PsiMethod superMethod, final Project project) { - @NonNls String name = method.getName(); - int ret = name.startsWith("annotateBase") ? 0 // yes, annotate all - : name.startsWith("dontAnnotateBase") ? 1 // do not annotate base - : 2; //abort - myMustBeAvailableAfterInvoke = ret == 2; - return ret; + protected AnnotateMethodFix createAnnotateMethodFix(String defaultNotNull, String[] annotationsToRemove) { + return new AnnotateMethodFix(defaultNotNull, annotationsToRemove){ + @Override + public int annotateBaseMethod(final PsiMethod method, final PsiMethod superMethod, final Project project) { + @NonNls String name = method.getName(); + int ret = name.startsWith("annotateBase") ? 0 // yes, annotate all + : name.startsWith("dontAnnotateBase") ? 1 // do not annotate base + : 2; //abort + myMustBeAvailableAfterInvoke = ret == 2; + return ret; + } + }; } + }}; } diff --git a/java/openapi/src/com/intellij/psi/CommonClassNames.java b/java/openapi/src/com/intellij/psi/CommonClassNames.java index da485d201129..664976bb0cb0 100644 --- a/java/openapi/src/com/intellij/psi/CommonClassNames.java +++ b/java/openapi/src/com/intellij/psi/CommonClassNames.java @@ -79,4 +79,5 @@ public interface CommonClassNames { @NonNls String CLASS_FILE_EXTENSION = ".class"; @NonNls String JAVA_UTIL_CONCURRENT_FUTURE = "java.util.concurrent.Future"; + @NonNls String JAVA_UTIL_ARRAY_LIST = "java.util.ArrayList"; } diff --git a/java/openapi/src/com/intellij/psi/PsiJavaParserFacade.java b/java/openapi/src/com/intellij/psi/PsiJavaParserFacade.java index 332f2f2928f2..7029a6ff4a60 100644 --- a/java/openapi/src/com/intellij/psi/PsiJavaParserFacade.java +++ b/java/openapi/src/com/intellij/psi/PsiJavaParserFacade.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.psi; import com.intellij.pom.java.LanguageLevel; @@ -22,8 +21,9 @@ import com.intellij.psi.javadoc.PsiDocTag; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -/* +/** * @author max */ public interface PsiJavaParserFacade extends PsiParserFacade { @@ -41,7 +41,7 @@ public interface PsiJavaParserFacade extends PsiParserFacade { * @deprecated use {@link #createDocTagFromText(String)} (to remove in IDEA 11) */ @NotNull - PsiDocTag createDocTagFromText(@NotNull String docTagText, PsiElement context) throws IncorrectOperationException; + PsiDocTag createDocTagFromText(@NotNull String docTagText, @Nullable PsiElement context) throws IncorrectOperationException; /** * Creates a JavaDoc comment from the specified text. @@ -57,7 +57,7 @@ public interface PsiJavaParserFacade extends PsiParserFacade { * @deprecated use {@link #createDocCommentFromText(String)} (to remove in IDEA 11) */ @NotNull - PsiDocComment createDocCommentFromText(@NotNull String docCommentText, PsiElement context) throws IncorrectOperationException; + PsiDocComment createDocCommentFromText(@NotNull String docCommentText, @Nullable PsiElement context) throws IncorrectOperationException; /** * Creates a Java class from the specified text. @@ -69,7 +69,7 @@ public interface PsiJavaParserFacade extends PsiParserFacade { * @throws com.intellij.util.IncorrectOperationException if the text is not a valid class body. */ @NotNull - PsiClass createClassFromText(@NotNull @NonNls String text, PsiElement context) throws IncorrectOperationException; + PsiClass createClassFromText(@NotNull @NonNls String text, @Nullable PsiElement context) throws IncorrectOperationException; /** * Creates a Java field from the specified text. @@ -80,7 +80,7 @@ public interface PsiJavaParserFacade extends PsiParserFacade { * @throws com.intellij.util.IncorrectOperationException if the text is not a valid field body. */ @NotNull - PsiField createFieldFromText(@NotNull @NonNls String text, PsiElement context) throws IncorrectOperationException; + PsiField createFieldFromText(@NotNull @NonNls String text, @Nullable PsiElement context) throws IncorrectOperationException; /** * Creates a Java method from the specified text with the specified language level. @@ -92,7 +92,7 @@ public interface PsiJavaParserFacade extends PsiParserFacade { * @throws com.intellij.util.IncorrectOperationException if the text is not a valid method body. */ @NotNull - PsiMethod createMethodFromText(@NotNull @NonNls String text, PsiElement context, LanguageLevel languageLevel) throws IncorrectOperationException; + PsiMethod createMethodFromText(@NotNull @NonNls String text, @Nullable PsiElement context, LanguageLevel languageLevel) throws IncorrectOperationException; /** * Creates a Java method from the specified text. @@ -103,7 +103,7 @@ public interface PsiJavaParserFacade extends PsiParserFacade { * @throws com.intellij.util.IncorrectOperationException if the text is not a valid method body. */ @NotNull - PsiMethod createMethodFromText(@NotNull @NonNls String text, PsiElement context) throws IncorrectOperationException; + PsiMethod createMethodFromText(@NotNull @NonNls String text, @Nullable PsiElement context) throws IncorrectOperationException; /** * Creates a Java parameter from the specified text. @@ -114,7 +114,7 @@ public interface PsiJavaParserFacade extends PsiParserFacade { * @throws com.intellij.util.IncorrectOperationException if the text is not a valid parameter body. */ @NotNull - PsiParameter createParameterFromText(@NotNull @NonNls String text, PsiElement context) throws IncorrectOperationException; + PsiParameter createParameterFromText(@NotNull @NonNls String text, @Nullable PsiElement context) throws IncorrectOperationException; /** * Creates a Java try-resource from the specified text. @@ -125,7 +125,7 @@ public interface PsiJavaParserFacade extends PsiParserFacade { * @throws com.intellij.util.IncorrectOperationException if the text is not a valid resource definition. */ @NotNull - PsiResourceVariable createResourceFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException; + PsiResourceVariable createResourceFromText(@NotNull String text, @Nullable PsiElement context) throws IncorrectOperationException; /** * Creates a Java type from the specified text. @@ -137,7 +137,7 @@ public interface PsiJavaParserFacade extends PsiParserFacade { * @throws com.intellij.util.IncorrectOperationException if the text does not specify a valid type. */ @NotNull - PsiType createTypeFromText(@NotNull @NonNls String text, PsiElement context) throws IncorrectOperationException; + PsiType createTypeFromText(@NotNull @NonNls String text, @Nullable PsiElement context) throws IncorrectOperationException; /** * Creates a Java type element from the specified text. @@ -149,7 +149,7 @@ public interface PsiJavaParserFacade extends PsiParserFacade { * @throws com.intellij.util.IncorrectOperationException if the text does not specify a valid type. */ @NotNull - PsiTypeElement createTypeElementFromText(@NotNull @NonNls String text, PsiElement context) throws IncorrectOperationException; + PsiTypeElement createTypeElementFromText(@NotNull @NonNls String text, @Nullable PsiElement context) throws IncorrectOperationException; /** * Creates a Java code reference from the specified text. @@ -161,7 +161,7 @@ public interface PsiJavaParserFacade extends PsiParserFacade { * @throws com.intellij.util.IncorrectOperationException if the text does not specify a valid type. */ @NotNull - PsiJavaCodeReferenceElement createReferenceFromText(@NotNull @NonNls String text, PsiElement context) throws IncorrectOperationException; + PsiJavaCodeReferenceElement createReferenceFromText(@NotNull @NonNls String text, @Nullable PsiElement context) throws IncorrectOperationException; /** * Creates a Java code block from the specified text. @@ -172,7 +172,7 @@ public interface PsiJavaParserFacade extends PsiParserFacade { * @throws com.intellij.util.IncorrectOperationException if the text does not specify a valid code block. */ @NotNull - PsiCodeBlock createCodeBlockFromText(@NotNull @NonNls String text, PsiElement context) throws IncorrectOperationException; + PsiCodeBlock createCodeBlockFromText(@NotNull @NonNls String text, @Nullable PsiElement context) throws IncorrectOperationException; /** * Creates a Java statement from the specified text. @@ -183,7 +183,7 @@ public interface PsiJavaParserFacade extends PsiParserFacade { * @throws com.intellij.util.IncorrectOperationException if the text does not specify a valid statement. */ @NotNull - PsiStatement createStatementFromText(@NotNull @NonNls String text, PsiElement context) throws IncorrectOperationException; + PsiStatement createStatementFromText(@NotNull @NonNls String text, @Nullable PsiElement context) throws IncorrectOperationException; /** * Creates a Java expression from the specified text. @@ -194,7 +194,7 @@ public interface PsiJavaParserFacade extends PsiParserFacade { * @throws com.intellij.util.IncorrectOperationException if the text does not specify a valid expression. */ @NotNull - PsiExpression createExpressionFromText(@NotNull @NonNls String text, PsiElement context) throws IncorrectOperationException; + PsiExpression createExpressionFromText(@NotNull @NonNls String text, @Nullable PsiElement context) throws IncorrectOperationException; /** * Creates a Java comment from the specified text. @@ -205,7 +205,7 @@ public interface PsiJavaParserFacade extends PsiParserFacade { * @throws com.intellij.util.IncorrectOperationException if the text does not specify a valid comment. */ @NotNull - PsiComment createCommentFromText(@NotNull String text, PsiElement context) throws IncorrectOperationException; + PsiComment createCommentFromText(@NotNull String text, @Nullable PsiElement context) throws IncorrectOperationException; /** * Creates a type parameter from the specified text. @@ -216,7 +216,7 @@ public interface PsiJavaParserFacade extends PsiParserFacade { * @throws com.intellij.util.IncorrectOperationException if the text does not specify a valid type parameter. */ @NotNull - PsiTypeParameter createTypeParameterFromText(@NotNull @NonNls String text, PsiElement context) throws IncorrectOperationException; + PsiTypeParameter createTypeParameterFromText(@NotNull @NonNls String text, @Nullable PsiElement context) throws IncorrectOperationException; /** * Creates an annotation from the specified text. @@ -227,11 +227,10 @@ public interface PsiJavaParserFacade extends PsiParserFacade { * @throws com.intellij.util.IncorrectOperationException if the text does not specify a valid annotation. */ @NotNull - PsiAnnotation createAnnotationFromText(@NotNull @NonNls String annotationText, PsiElement context) throws IncorrectOperationException; + PsiAnnotation createAnnotationFromText(@NotNull @NonNls String annotationText, @Nullable PsiElement context) throws IncorrectOperationException; @NotNull - PsiEnumConstant createEnumConstantFromText(@NotNull String text, PsiElement context) throws IncorrectOperationException; - + PsiEnumConstant createEnumConstantFromText(@NotNull String text, @Nullable PsiElement context) throws IncorrectOperationException; /** * Creates a catch section for catching an exception of the specified @@ -243,8 +242,8 @@ public interface PsiJavaParserFacade extends PsiParserFacade { * @return the created catch section instance. * @throws IncorrectOperationException if some of the parameters are not valid. */ - @NotNull PsiCatchSection createCatchSection(@NotNull PsiClassType exceptionType, @NotNull String exceptionName, PsiElement context) - throws IncorrectOperationException; + @NotNull + PsiCatchSection createCatchSection(@NotNull PsiClassType exceptionType, @NotNull String exceptionName, @Nullable PsiElement context) throws IncorrectOperationException; /** * Creates a Java type from the specified text. @@ -254,5 +253,6 @@ public interface PsiJavaParserFacade extends PsiParserFacade { * @return the created type instance. * @throws IncorrectOperationException if some of the parameters are not valid. */ + @NotNull PsiType createPrimitiveType(@NotNull String text, @NotNull PsiAnnotation[] annotations) throws IncorrectOperationException; } diff --git a/java/testFramework/src/com/intellij/codeInsight/daemon/DaemonAnalyzerTestCase.java b/java/testFramework/src/com/intellij/codeInsight/daemon/DaemonAnalyzerTestCase.java index 08daa1cc75a4..1ce2f15b1870 100644 --- a/java/testFramework/src/com/intellij/codeInsight/daemon/DaemonAnalyzerTestCase.java +++ b/java/testFramework/src/com/intellij/codeInsight/daemon/DaemonAnalyzerTestCase.java @@ -169,8 +169,10 @@ public abstract class DaemonAnalyzerTestCase extends CodeInsightTestCase { DaemonCodeAnalyzerImpl daemonCodeAnalyzer = (DaemonCodeAnalyzerImpl)DaemonCodeAnalyzer.getInstance(getProject()); toInitializeDaemon = !daemonCodeAnalyzer.isInitialized(); daemonCodeAnalyzer.prepareForTest(toInitializeDaemon); - ((StartupManagerImpl)StartupManagerEx.getInstanceEx(getProject())).runStartupActivities(); - ((StartupManagerImpl)StartupManagerEx.getInstanceEx(getProject())).runPostStartupActivities(); + final StartupManagerImpl startupManager = (StartupManagerImpl)StartupManagerEx.getInstanceEx(getProject()); + startupManager.runStartupActivities(); + startupManager.startCacheUpdate(); + startupManager.runPostStartupActivities(); DaemonCodeAnalyzerSettings.getInstance().setImportHintEnabled(false); if (isPerformanceTest()) { diff --git a/java/testFramework/src/com/intellij/refactoring/move/moveMembers/MockMoveMembersOptions.java b/java/testFramework/src/com/intellij/refactoring/move/moveMembers/MockMoveMembersOptions.java index b10bc2e57495..bc6b7473ad2b 100644 --- a/java/testFramework/src/com/intellij/refactoring/move/moveMembers/MockMoveMembersOptions.java +++ b/java/testFramework/src/com/intellij/refactoring/move/moveMembers/MockMoveMembersOptions.java @@ -17,6 +17,7 @@ package com.intellij.refactoring.move.moveMembers; import com.intellij.psi.PsiMember; import com.intellij.psi.PsiModifier; +import org.jetbrains.annotations.Nullable; import java.util.Collection; @@ -47,7 +48,7 @@ public class MockMoveMembersOptions implements MoveMembersOptions { return true; } - public void setMemberVisibility(String visibility) { + public void setMemberVisibility(@Nullable String visibility) { myMemberVisibility = visibility; } @@ -60,5 +61,4 @@ public class MockMoveMembersOptions implements MoveMembersOptions { public String getTargetClassName() { return myTargetClassName; } - } diff --git a/platform/icons/src/actions/checked.png b/platform/icons/src/actions/checked.png index 366b1b532cd6..0cdacea486cb 100644 Binary files a/platform/icons/src/actions/checked.png and b/platform/icons/src/actions/checked.png differ diff --git a/platform/icons/src/actions/checked_selected.png b/platform/icons/src/actions/checked_selected.png new file mode 100644 index 000000000000..59042e8c0308 Binary files /dev/null and b/platform/icons/src/actions/checked_selected.png differ diff --git a/platform/icons/src/actions/checked_small.png b/platform/icons/src/actions/checked_small.png new file mode 100644 index 000000000000..366b1b532cd6 Binary files /dev/null and b/platform/icons/src/actions/checked_small.png differ diff --git a/platform/icons/src/actions/checked_small_selected.png b/platform/icons/src/actions/checked_small_selected.png new file mode 100644 index 000000000000..7911a95b4192 Binary files /dev/null and b/platform/icons/src/actions/checked_small_selected.png differ diff --git a/platform/lang-api/src/com/intellij/codeInsight/completion/SkipAutopopupInStrings.java b/platform/lang-api/src/com/intellij/codeInsight/completion/SkipAutopopupInStrings.java new file mode 100644 index 000000000000..e6eab89815c8 --- /dev/null +++ b/platform/lang-api/src/com/intellij/codeInsight/completion/SkipAutopopupInStrings.java @@ -0,0 +1,54 @@ +/* + * 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.codeInsight.completion; + +import com.intellij.lang.LanguageParserDefinitions; +import com.intellij.lang.ParserDefinition; +import com.intellij.patterns.ElementPattern; +import com.intellij.patterns.PlatformPatterns; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.util.PsiUtilBase; +import com.intellij.util.ThreeState; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author peter + */ +public class SkipAutopopupInStrings extends CompletionConfidence { + @NotNull + @Override + public ThreeState shouldFocusLookup(@NotNull CompletionParameters parameters) { + return ThreeState.UNSURE; + } + + @NotNull + @Override + public ThreeState shouldSkipAutopopup(@Nullable PsiElement contextElement, @NotNull PsiFile psiFile, int offset) { + if (contextElement != null) { + ParserDefinition definition = LanguageParserDefinitions.INSTANCE.forLanguage(PsiUtilBase.getLanguageAtOffset(psiFile, offset)); + if (definition != null) { + ElementPattern pattern = PlatformPatterns.psiElement().withElementType(definition.getStringLiteralElements()); + if (pattern.accepts(contextElement) || pattern.accepts(contextElement.getParent())) { + return ThreeState.YES; + } + } + } + + return ThreeState.UNSURE; + } +} diff --git a/platform/lang-api/src/com/intellij/execution/ui/layout/LayoutViewOptions.java b/platform/lang-api/src/com/intellij/execution/ui/layout/LayoutViewOptions.java index d312a3186ab4..900d4b929a93 100644 --- a/platform/lang-api/src/com/intellij/execution/ui/layout/LayoutViewOptions.java +++ b/platform/lang-api/src/com/intellij/execution/ui/layout/LayoutViewOptions.java @@ -16,11 +16,11 @@ package com.intellij.execution.ui.layout; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import com.intellij.openapi.actionSystem.ActionGroup; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.ui.content.Content; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public interface LayoutViewOptions { diff --git a/platform/lang-api/src/com/intellij/lang/DefaultWordCompletionFilter.java b/platform/lang-api/src/com/intellij/lang/DefaultWordCompletionFilter.java index 813c893c80c2..10748cde4272 100644 --- a/platform/lang-api/src/com/intellij/lang/DefaultWordCompletionFilter.java +++ b/platform/lang-api/src/com/intellij/lang/DefaultWordCompletionFilter.java @@ -25,11 +25,6 @@ import com.intellij.psi.tree.IElementType; public class DefaultWordCompletionFilter implements WordCompletionElementFilter { public boolean isWordCompletionEnabledIn(final IElementType element) { - final CompletionProcess process = CompletionService.getCompletionService().getCurrentCompletion(); - if (process != null && process.isAutopopupCompletion()) { - return false; - } - final ParserDefinition parserDefinition = LanguageParserDefinitions.INSTANCE.forLanguage(element.getLanguage()); return parserDefinition != null && parserDefinition.getCommentTokens().contains(element); } diff --git a/platform/lang-api/src/com/intellij/psi/search/SingleTargetRequestResultProcessor.java b/platform/lang-api/src/com/intellij/psi/search/SingleTargetRequestResultProcessor.java index 9c9628ec91da..edd55f417dfe 100644 --- a/platform/lang-api/src/com/intellij/psi/search/SingleTargetRequestResultProcessor.java +++ b/platform/lang-api/src/com/intellij/psi/search/SingleTargetRequestResultProcessor.java @@ -7,6 +7,8 @@ import com.intellij.psi.ReferenceRange; import com.intellij.util.Processor; import org.jetbrains.annotations.NotNull; +import java.util.List; + /** * @author peter */ @@ -20,7 +22,9 @@ public final class SingleTargetRequestResultProcessor extends RequestResultProce } public boolean processTextOccurrence(PsiElement element, int offsetInElement, final Processor consumer) { - for (PsiReference ref : ourReferenceService.getReferences(element, new PsiReferenceService.Hints(myTarget, offsetInElement))) { + final List references = ourReferenceService.getReferences(element, + new PsiReferenceService.Hints(myTarget, offsetInElement)); + for (PsiReference ref : references) { if (ReferenceRange.containsOffsetInElement(ref, offsetInElement)) { if (ref.isReferenceTo(myTarget)) { if (!consumer.process(ref)) { diff --git a/platform/lang-impl/src/com/intellij/application/options/GeneralCodeStylePanel.java b/platform/lang-impl/src/com/intellij/application/options/GeneralCodeStylePanel.java index 7d71ea12375e..9e76d183d11c 100644 --- a/platform/lang-impl/src/com/intellij/application/options/GeneralCodeStylePanel.java +++ b/platform/lang-impl/src/com/intellij/application/options/GeneralCodeStylePanel.java @@ -218,8 +218,12 @@ public class GeneralCodeStylePanel extends CodeStyleAbstractPanel { for(Map.Entry entry : myAdditionalIndentOptions.entrySet()) { FileType fileType = entry.getKey(); + CodeStyleSettings.IndentOptions additionalIndentOptions = settings.getAdditionalIndentOptions(fileType); + if (additionalIndentOptions == null) { + continue; + } IndentOptionsEditor editor = entry.getValue(); - editor.apply(settings, settings.getAdditionalIndentOptions(fileType)); + editor.apply(settings, additionalIndentOptions); } } @@ -279,9 +283,13 @@ public class GeneralCodeStylePanel extends CodeStyleAbstractPanel { } for(Map.Entry entry : myAdditionalIndentOptions.entrySet()) { - IndentOptionsEditor editor = entry.getValue(); FileType fileType = entry.getKey(); - if (editor.isModified(settings, settings.getAdditionalIndentOptions(fileType))) { + CodeStyleSettings.IndentOptions additionalIndentOptions = settings.getAdditionalIndentOptions(fileType); + if (additionalIndentOptions == null) { + continue; + } + IndentOptionsEditor editor = entry.getValue(); + if (editor.isModified(settings, additionalIndentOptions)) { return true; } } diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/OptionTableWithPreviewPanel.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/OptionTableWithPreviewPanel.java index 97289c509187..f324d6594b2c 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/OptionTableWithPreviewPanel.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/OptionTableWithPreviewPanel.java @@ -621,6 +621,7 @@ public abstract class OptionTableWithPreviewPanel extends MultilanguageCodeStyle } }); myBooleanEditor.putClientProperty("JComponent.sizeVariant", "small"); + myOptionsEditor.putClientProperty("JComponent.sizeVariant", "small"); } public Object getCellEditorValue() { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/WordCompletionContributor.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/WordCompletionContributor.java index b43ed802a0ca..1b4de9688e44 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/WordCompletionContributor.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/WordCompletionContributor.java @@ -19,7 +19,6 @@ import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElementBuilder; import com.intellij.lang.ASTNode; import com.intellij.lang.LanguageWordCompletion; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.DumbService; import com.intellij.psi.PlainTextTokenTypes; @@ -71,6 +70,10 @@ public class WordCompletionContributor extends CompletionContributor implements return true; } + if (parameters.getInvocationCount() == 0) { + return false; + } + final PsiFile file = insertedElement.getContainingFile(); final CompletionData data = CompletionUtil.getCompletionDataByElement(insertedElement, file); if (data != null && !(data instanceof SyntaxTableCompletionData)) { @@ -95,8 +98,7 @@ public class WordCompletionContributor extends CompletionContributor implements ASTNode textContainer = element != null ? element.getNode() : null; while (textContainer != null) { final IElementType elementType = textContainer.getElementType(); - if (LanguageWordCompletion.INSTANCE.isEnabledIn(elementType) || - isPlainText(parameters, elementType)) { + if (LanguageWordCompletion.INSTANCE.isEnabledIn(elementType) || elementType == PlainTextTokenTypes.PLAIN_TEXT) { return true; } textContainer = textContainer.getTreeParent(); @@ -104,19 +106,4 @@ public class WordCompletionContributor extends CompletionContributor implements return false; } - private static boolean isPlainText(CompletionParameters parameters, IElementType elementType) { - if (elementType != PlainTextTokenTypes.PLAIN_TEXT) { - return false; - } - - if (ApplicationManager.getApplication().isUnitTestMode()) { - return true; - } - - if (parameters.getInvocationCount() > 0) { - return true; - } - - return parameters.getOriginalFile().getViewProvider().getVirtualFile().isInLocalFileSystem(); - } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/EmacsStyleIndentAction.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/EmacsStyleIndentAction.java index bbfc43917200..7121fcbcf80e 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/EmacsStyleIndentAction.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/EmacsStyleIndentAction.java @@ -18,6 +18,8 @@ package com.intellij.codeInsight.editorActions; import com.intellij.codeInsight.CodeInsightActionHandler; import com.intellij.codeInsight.actions.BaseCodeInsightAction; +import com.intellij.codeInsight.editorActions.emacs.EmacsProcessingHandler; +import com.intellij.codeInsight.editorActions.emacs.LanguageEmacsExtension; import com.intellij.lang.LanguageFormatting; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; @@ -57,6 +59,14 @@ public class EmacsStyleIndentAction extends BaseCodeInsightAction implements Dum return; } + EmacsProcessingHandler emacsProcessingHandler = LanguageEmacsExtension.INSTANCE.forLanguage(file.getLanguage()); + if (emacsProcessingHandler != null) { + EmacsProcessingHandler.Result result = emacsProcessingHandler.changeIndent(project, editor, file); + if (result == EmacsProcessingHandler.Result.STOP) { + return; + } + } + final Document document = editor.getDocument(); final int startOffset = editor.getCaretModel().getOffset(); final int line = editor.offsetToLogicalPosition(startOffset).line; diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/JoinLinesHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/JoinLinesHandler.java index 2ea11eb84164..98d122dc3b54 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/JoinLinesHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/JoinLinesHandler.java @@ -28,7 +28,6 @@ import com.intellij.ide.DataManager; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.LogicalPosition; import com.intellij.openapi.editor.ScrollType; @@ -43,7 +42,6 @@ import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.codeStyle.CodeStyleManager; -import com.intellij.psi.impl.source.codeStyle.CodeEditUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; @@ -96,6 +94,7 @@ public class JoinLinesHandler extends EditorWriteActionHandler { if (i >= doc.getLineCount() - 1) break; int lineEndOffset = doc.getLineEndOffset(startLine); + docManager.doPostponedOperationsAndUnblockDocument(doc); docManager.commitDocument(doc); CharSequence text = doc.getCharsSequence(); int firstNonSpaceOffsetInNextLine = doc.getLineStartOffset(startLine + 1); @@ -120,7 +119,7 @@ public class JoinLinesHandler extends EditorWriteActionHandler { TextRange limits = findStartAndEnd(text, lastNonSpaceOffsetInStartLine, firstNonSpaceOffsetInNextLine, doc.getTextLength()); start = limits.getStartOffset(); end = limits.getEndOffset(); // run raw joiners - for(JoinLinesHandlerDelegate delegate: Extensions.getExtensions(JoinRawLinesHandlerDelegate.EP_NAME)) { + for(JoinLinesHandlerDelegate delegate: Extensions.getExtensions(JoinLinesHandlerDelegate.EP_NAME)) { if (delegate instanceof JoinRawLinesHandlerDelegate) { rc = ((JoinRawLinesHandlerDelegate)delegate).tryJoinRawLines(doc, psiFile, start, end); if (rc != CANNOT_JOIN) { @@ -239,16 +238,16 @@ public class JoinLinesHandler extends EditorWriteActionHandler { } private static void doPostponedOperationsAndUnblockDocument(@NotNull PsiDocumentManager docManager, @NotNull DocumentEx document) { - boolean restore = CodeEditUtil.isSuspendedNodesReformattingAllowed(); - CodeEditUtil.setAllowSuspendNodesReformatting(false); - try { + //boolean restore = CodeEditUtil.isSuspendedNodesReformattingAllowed(); + //CodeEditUtil.setAllowSuspendNodesReformatting(false); + //try { docManager.doPostponedOperationsAndUnblockDocument(document); - } - finally { - if (restore) { - CodeEditUtil.setAllowSuspendNodesReformatting(true); - } - } + //} + //finally { + // if (restore) { + // CodeEditUtil.setAllowSuspendNodesReformatting(true); + // } + //} } private static boolean isCommentElement(final PsiElement element) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/SelectWordUtil.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/SelectWordUtil.java index 938b42fe5d8d..31e22d90a43f 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/SelectWordUtil.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/SelectWordUtil.java @@ -34,6 +34,9 @@ public class SelectWordUtil { private static boolean ourExtensionsLoaded = false; + private SelectWordUtil() { + } + public static void registerSelectioner(ExtendWordSelectionHandler selectioner) { SELECTIONERS = ArrayUtil.append(SELECTIONERS, selectioner); } @@ -60,7 +63,11 @@ public class SelectWordUtil { } } + @Nullable private static TextRange getCamelSelectionRange(CharSequence editorText, int cursorOffset) { + if (cursorOffset < 0 || cursorOffset >= editorText.length()) { + return null; + } if (cursorOffset > 0 && !Character.isJavaIdentifierPart(editorText.charAt(cursorOffset)) && Character.isJavaIdentifierPart(editorText.charAt(cursorOffset - 1))) { cursorOffset--; diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/emacs/DefaultEmacsProcessingHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/emacs/DefaultEmacsProcessingHandler.java new file mode 100644 index 000000000000..63f842a369e7 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/emacs/DefaultEmacsProcessingHandler.java @@ -0,0 +1,34 @@ +/* + * 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.codeInsight.editorActions.emacs; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.NotNull; + +/** + * @author Denis Zhdanov + * @since 4/11/11 2:36 PM + */ +public class DefaultEmacsProcessingHandler implements EmacsProcessingHandler { + + @NotNull + @Override + public Result changeIndent(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) { + return Result.CONTINUE; + } +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/emacs/EmacsProcessingHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/emacs/EmacsProcessingHandler.java new file mode 100644 index 000000000000..c527150b8325 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/emacs/EmacsProcessingHandler.java @@ -0,0 +1,62 @@ +/* + * 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.codeInsight.editorActions.emacs; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.NotNull; + +/** + * This interface is assumed to define general contract for Emacs-like functionality. + * + * @author Denis Zhdanov + * @since 4/11/11 1:56 PM + */ +public interface EmacsProcessingHandler { + + /** + * Enumerates possible processing results. + */ + enum Result { + /** + * Proceed to the next handler in a chain. + */ + CONTINUE, + + /** + * Stop current processing as everything is done by the current handler + */ + STOP + } + + /** + * Emacs handles Tab pressing as + * 'auto indent line' + * most of the time. However, there are extensions to this like python-mode + * that changes indentation level of the current line (makes it belong to the other code block). + *

+ * So, current method may be implemented by changing code block for the active line by changing its indentation. + * {@link Result#STOP} should be returned then. + * + * @param project current project + * @param editor current editor + * @param file current file + * @return processing result + */ + @NotNull + Result changeIndent(@NotNull final Project project, @NotNull final Editor editor, @NotNull final PsiFile file); +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/emacs/LanguageEmacsExtension.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/emacs/LanguageEmacsExtension.java new file mode 100644 index 000000000000..1a7d6268b2ff --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/emacs/LanguageEmacsExtension.java @@ -0,0 +1,32 @@ +/* + * 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.codeInsight.editorActions.emacs; + +import com.intellij.lang.LanguageExtension; + +/** + * @author Denis Zhdanov + * @since 4/11/11 2:21 PM + */ +public class LanguageEmacsExtension extends LanguageExtension { + + public static final String EP_NAME = "com.intellij.lang.emacs"; + public static final LanguageEmacsExtension INSTANCE = new LanguageEmacsExtension(); + + public LanguageEmacsExtension() { + super(EP_NAME, new DefaultEmacsProcessingHandler()); + } +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java index a2775f74286b..d96a658c88fc 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java @@ -20,6 +20,7 @@ import com.intellij.codeInsight.CodeInsightBundle; import com.intellij.codeInsight.completion.CompletionLookupArranger; import com.intellij.codeInsight.completion.PrefixMatcher; import com.intellij.codeInsight.completion.impl.CamelHumpMatcher; +import com.intellij.codeInsight.editorActions.CompletionAutoPopupHandler; import com.intellij.codeInsight.hint.HintManager; import com.intellij.codeInsight.hint.HintManagerImpl; import com.intellij.codeInsight.lookup.*; @@ -124,6 +125,7 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable { private JLabel mySortingLabel; private final JScrollPane myScrollPane; private JButton myScrollBarIncreaseButton; + private boolean myStartCompletionWhenNothingMatches; public LookupImpl(Project project, Editor editor, @NotNull LookupArranger arranger){ super(new JPanel(new BorderLayout())); @@ -328,6 +330,13 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable { myFrozenItems.clear(); refreshUi(); ensureSelectionVisible(); + if (myStartCompletionWhenNothingMatches && myList.getModel().getSize() == 1 && myList.getModel().getElementAt(0) instanceof EmptyLookupItem) { + CompletionAutoPopupHandler.scheduleAutoPopup(myProject, myEditor, getPsiFile()); + } + } + + public void setStartCompletionWhenNothingMatches(boolean startCompletionWhenNothingMatches) { + myStartCompletionWhenNothingMatches = startCompletionWhenNothingMatches; } private void ensureSelectionVisible() { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupManagerImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupManagerImpl.java index 48c5e91d9aa6..43025279fe71 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupManagerImpl.java @@ -113,6 +113,9 @@ public class LookupManagerImpl extends LookupManager { final LookupImpl lookup = createLookup(editor, items, prefix, arranger); lookup.show(); + if (CodeInsightSettings.getInstance().AUTO_POPUP_COMPLETION_LOOKUP) { + lookup.setStartCompletionWhenNothingMatches(true); + } return lookup; } diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextImpl.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextImpl.java index c5271749f496..7f993a74af38 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextImpl.java @@ -321,7 +321,7 @@ public class GlobalInspectionContextImpl extends UserDataHolderBase implements G new File(outputPath).mkdirs(); final File file = new File(outputPath, toolName + ext); if (isLocalTool) { - FileUtil.writeToFile(file, ""); + FileUtil.writeToFile(file, ("").getBytes("UTF-8"), true); } else { PathMacroManager.getInstance(getProject()).collapsePaths(doc.getRootElement()); diff --git a/platform/lang-impl/src/com/intellij/execution/console/ConsoleHistoryController.java b/platform/lang-impl/src/com/intellij/execution/console/ConsoleHistoryController.java index 94c2086dd306..ca98abdf0048 100644 --- a/platform/lang-impl/src/com/intellij/execution/console/ConsoleHistoryController.java +++ b/platform/lang-impl/src/com/intellij/execution/console/ConsoleHistoryController.java @@ -285,7 +285,7 @@ public class ConsoleHistoryController { } private void saveHistory(final XmlSerializer out) throws IOException { - out.startDocument(System.getProperty(CharsetToolkit.FILE_ENCODING_PROPERTY), null); + out.startDocument("UTF8", null); out.startTag(null, "console-history"); out.attribute(null, "id", myId); for (String s : myModel.getHistory()) { diff --git a/platform/lang-impl/src/com/intellij/execution/impl/ConsoleBuffer.java b/platform/lang-impl/src/com/intellij/execution/impl/ConsoleBuffer.java index 6a50c4d0bb42..28e5ecfb07f0 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/ConsoleBuffer.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/ConsoleBuffer.java @@ -95,7 +95,9 @@ public class ConsoleBuffer { private int myDeferredOutputLength; /** - * Buffer for deferred stdin and stderr output. + * Buffer for deferred stdin output. + *

+ * Is assumed to store user input data until it's delivered to the target process. That activity is driven from outside this class. */ private StringBuffer myDeferredUserInput = new StringBuffer(); @@ -201,6 +203,10 @@ public class ConsoleBuffer { } public void clear() { + clear(true); + } + + public void clear(boolean clearUserInputAsWell) { if (myUseCyclicBuffer) { myDeferredOutput.clear(); myDeferredOutput.add(new StringBuilder(myCyclicBufferUnitSize)); @@ -212,8 +218,10 @@ public class ConsoleBuffer { } myDeferredOutputLength = 0; myDeferredTypes.clear(); - myDeferredUserInput = new StringBuffer(); myDeferredTokens.clear(); + if (clearUserInputAsWell) { + myDeferredUserInput = new StringBuffer(); + } } @Nullable diff --git a/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java b/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java index c2c091863bc6..401ce8fda28a 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java @@ -563,7 +563,7 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo addToken(deferredToken.getLength(), deferredToken.getHyperlinkInfo(), deferredToken.contentType); } deferredTokensSize = deferredTokens.size(); - myBuffer.clear(); + myBuffer.clear(false); } final Document document = myEditor.getDocument(); final int oldLineCount = document.getLineCount(); diff --git a/platform/lang-impl/src/com/intellij/find/FindUtil.java b/platform/lang-impl/src/com/intellij/find/FindUtil.java index 15d2712b1db7..f8e5207a4dcb 100644 --- a/platform/lang-impl/src/com/intellij/find/FindUtil.java +++ b/platform/lang-impl/src/com/intellij/find/FindUtil.java @@ -96,30 +96,27 @@ public class FindUtil { } public static void configureFindModel(boolean replace, Editor editor, FindModel model) { - String selectedText = editor.getSelectionModel().getSelectedText(); - model.setReplaceState(replace); - if (selectedText != null) { - if (replace) { - if (!StringUtil.isEmpty(selectedText)) { - if (selectedText.indexOf('\n') >= 0) { - model.setGlobal(false); - } - else { - model.setStringToFind(selectedText); - model.setGlobal(true); - } - } else { - model.setGlobal(true); - } - } else { - model.setStringToFind(selectedText); - model.setGlobal(true); - } + final String selectedText = editor.getSelectionModel().getSelectedText(); - if (model.isGlobal()) { - model.setStringToFind(selectedText); + boolean isGlobal = true; + String stringToFind = null; + if (!StringUtil.isEmpty(selectedText)) { + if (selectedText.indexOf('\n') >= 0) { + if (replace){ + isGlobal = false; + stringToFind = model.getStringToFind(); + } } + if (stringToFind == null) { + stringToFind = selectedText; + } + } else { + stringToFind = model.getStringToFind(); } + + model.setReplaceState(replace); + model.setStringToFind(stringToFind); + model.setGlobal(isGlobal); model.setPromptOnReplace(false); } diff --git a/platform/lang-impl/src/com/intellij/find/findUsages/CustomUsageSearcher.java b/platform/lang-impl/src/com/intellij/find/findUsages/CustomUsageSearcher.java new file mode 100644 index 000000000000..61b2b5f6f291 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/find/findUsages/CustomUsageSearcher.java @@ -0,0 +1,31 @@ +/* + * 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.find.findUsages; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.psi.PsiElement; +import com.intellij.usages.Usage; +import com.intellij.util.Processor; + +/** + * @author gregsh + */ +public abstract class CustomUsageSearcher { + public static final ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.customUsageSearcher"); + + public abstract void processElementUsages(final PsiElement element, final Processor processor, final FindUsagesOptions options); +} diff --git a/platform/lang-impl/src/com/intellij/find/findUsages/FindUsagesManager.java b/platform/lang-impl/src/com/intellij/find/findUsages/FindUsagesManager.java index 5bff937c484d..8748875b854d 100644 --- a/platform/lang-impl/src/com/intellij/find/findUsages/FindUsagesManager.java +++ b/platform/lang-impl/src/com/intellij/find/findUsages/FindUsagesManager.java @@ -380,6 +380,14 @@ public class FindUsagesManager implements JDOMExternalizable { } }); handler.processElementUsages(element, usageInfoProcessor, options); + for (CustomUsageSearcher searcher : Extensions.getExtensions(CustomUsageSearcher.EP_NAME)) { + try { + searcher.processElementUsages(element, processor, options); + } + catch (Exception e) { + LOG.error(e); + } + } } Project project = ApplicationManager.getApplication().runReadAction(new Computable() { diff --git a/platform/lang-impl/src/com/intellij/find/impl/FindDialog.java b/platform/lang-impl/src/com/intellij/find/impl/FindDialog.java index 0f818f3e59f6..b713ee70980c 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/FindDialog.java +++ b/platform/lang-impl/src/com/intellij/find/impl/FindDialog.java @@ -97,7 +97,7 @@ class FindDialog extends DialogWrapper { private final FindModel myModel; private final Runnable myOkHandler; private FixedSizeButton mySelectDirectoryButton; - private StateRestoringCheckBox useFileFilter; + private StateRestoringCheckBox myUseFileFilter; private ComboBox myFileFilter; private JCheckBox myCbToSkipResultsWhenOneUsage; private final Project myProject; @@ -405,7 +405,7 @@ class FindDialog extends DialogWrapper { myFileFilter = new ComboBox(100); initCombobox(myFileFilter); - filterPanel.add(useFileFilter = createCheckbox(FindBundle.message("find.filter.file.mask.checkbox")),BorderLayout.WEST); + filterPanel.add(myUseFileFilter = createCheckbox(FindBundle.message("find.filter.file.mask.checkbox")),BorderLayout.WEST); filterPanel.add(myFileFilter,BorderLayout.CENTER); myFileFilter.setEditable(true); String[] fileMasks = FindSettings.getInstance().getRecentFileMasks(); @@ -414,10 +414,10 @@ class FindDialog extends DialogWrapper { } myFileFilter.setEnabled(false); - useFileFilter.addActionListener( + myUseFileFilter.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { - if (!useFileFilter.isSelected()) { + if (!myUseFileFilter.isSelected()) { myFileFilter.setEnabled(false); } else { myFileFilter.setEnabled(true); @@ -533,7 +533,7 @@ class FindDialog extends DialogWrapper { } } - final String mask = myFileFilter == null ? null : (String)myFileFilter.getSelectedItem(); + final String mask = (myFileFilter == null || !myUseFileFilter.isSelected()) ? null : (String)myFileFilter.getSelectedItem(); if (mask != null) { if (mask.length() == 0) { @@ -1031,7 +1031,7 @@ class FindDialog extends DialogWrapper { model.setFindAll(findAll); String mask = null; - if (useFileFilter!=null && useFileFilter.isSelected()) { + if (myUseFileFilter !=null && myUseFileFilter.isSelected()) { mask = (String)myFileFilter.getSelectedItem(); } model.setFileFilter(mask); @@ -1109,7 +1109,7 @@ class FindDialog extends DialogWrapper { if (myModel.getFileFilter()!=null && myModel.getFileFilter().length() > 0) { myFileFilter.setSelectedItem(myModel.getFileFilter()); myFileFilter.setEnabled(true); - useFileFilter.setSelected(true); + myUseFileFilter.setSelected(true); } } else { diff --git a/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewControllerBase.java b/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewControllerBase.java index 5a58b33cb458..874996687195 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewControllerBase.java +++ b/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewControllerBase.java @@ -138,7 +138,9 @@ public class LivePreviewControllerBase implements LivePreview.Delegate, FindUtil myLivePreviewAlarm.cancelAllRequests(); if (findModel == null) return; final boolean unitTestMode = ApplicationManager.getApplication().isUnitTestMode(); - final FindModel copy = (FindModel)findModel.clone(); + final FindModel copy = new FindModel(); + copy.copyFrom(findModel); + final ModalityState modalityState = ModalityState.current(); Runnable request = new Runnable() { @Override @@ -219,9 +221,21 @@ public class LivePreviewControllerBase implements LivePreview.Delegate, FindUtil public void performReplaceAll(Editor e) { if (!Utils.ensureOkToWrite(e)) return; if (mySearchResults.getFindModel() != null) { - FindUtil.replace(e.getProject(), e, - mySearchResults.getFindModel().isGlobal() ? 0 : mySearchResults.getEditor().getSelectionModel().getSelectionStart(), - mySearchResults.getFindModel(), this); + final FindModel copy = new FindModel(); + copy.copyFrom(mySearchResults.getFindModel()); + + final SelectionModel selectionModel = mySearchResults.getEditor().getSelectionModel(); + + int offset; + if (selectionModel.getSelectedText() != null) { + offset = selectionModel.getSelectionStart(); + } else { + offset = 0; + copy.setGlobal(true); + } + + FindUtil.replace(e.getProject(), e, offset, copy, this); + if (myReplaceListener != null) { myReplaceListener.replaceAllPerformed(e); } diff --git a/platform/lang-impl/src/com/intellij/formatting/AbstractBlockWrapper.java b/platform/lang-impl/src/com/intellij/formatting/AbstractBlockWrapper.java index cf0773617e46..debe73fdb099 100644 --- a/platform/lang-impl/src/com/intellij/formatting/AbstractBlockWrapper.java +++ b/platform/lang-impl/src/com/intellij/formatting/AbstractBlockWrapper.java @@ -21,13 +21,21 @@ import com.intellij.psi.codeStyle.CodeStyleSettings; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; + +import static java.util.Arrays.asList; /** * @author lesya */ public abstract class AbstractBlockWrapper { + private static final Set RELATIVE_INDENT_TYPES = new HashSet(asList( + Indent.Type.NORMAL, Indent.Type.CONTINUATION, Indent.Type.CONTINUATION_WITHOUT_FIRST + )); + protected WhiteSpace myWhiteSpace; protected CompositeBlockWrapper myParent; protected int myStart; @@ -158,41 +166,40 @@ public abstract class AbstractBlockWrapper { public IndentData getChildOffset(AbstractBlockWrapper child, CodeStyleSettings.IndentOptions options, int targetBlockStartOffset) { final boolean childStartsNewLine = child.getWhiteSpace().containsLineFeeds(); + IndentImpl.Type childIndentType = child.getIndent().getType(); IndentData childIndent; // Calculate child indent. - if (childStartsNewLine) { + if (childStartsNewLine + || (!getWhiteSpace().containsLineFeeds() && RELATIVE_INDENT_TYPES.contains(childIndentType) && indentAlreadyUsedBefore(child))) + { childIndent = getIndent(options, child, targetBlockStartOffset); } - else { - childIndent = new IndentData(0); - } - - // Enforce indent if child doesn't start new line, e.g. prefer the code below: - // void test() { - // foo("test", new Runnable() { - // public void run() { - // } - // }, - // new Runnable() { - // public void run() { - // } - // } - // ); - // } - // to this one: - // void test() { - // foo("test", new Runnable() { - // public void run() { - // } - // }, - // new Runnable() { - // public void run() { - // } - // } - // ); - // } - if (child.getIndent().isEnforceIndentToChildren() && !child.getWhiteSpace().containsLineFeeds()) { + else if (child.getIndent().isEnforceIndentToChildren() && !child.getWhiteSpace().containsLineFeeds()) { + // Enforce indent if child doesn't start new line, e.g. prefer the code below: + // void test() { + // foo("test", new Runnable() { + // public void run() { + // } + // }, + // new Runnable() { + // public void run() { + // } + // } + // ); + // } + // to this one: + // void test() { + // foo("test", new Runnable() { + // public void run() { + // } + // }, + // new Runnable() { + // public void run() { + // } + // } + // ); + // } AlignmentImpl alignment = child.getAlignment(); if (alignment != null) { // Generally, we want to handle situation like the one below: @@ -209,7 +216,7 @@ public abstract class AbstractBlockWrapper { // ); // I.e. we want 'run()' method from the first anonymous class to be aligned with the 'run()' method of the second anonymous class. - AbstractBlockWrapper anchorBlock = alignment.getOffsetRespBlockBefore(child); + AbstractBlockWrapper anchorBlock = alignment.getOffsetRespBlockBefore(child); if (anchorBlock == null) { anchorBlock = this; if (anchorBlock instanceof CompositeBlockWrapper) { @@ -224,7 +231,10 @@ public abstract class AbstractBlockWrapper { } return anchorBlock.getNumberOfSymbolsBeforeBlock(); } - childIndent = childIndent.add(getIndent(options, child, getStartOffset())); + childIndent = getIndent(options, child, getStartOffset()); + } + else { + childIndent = new IndentData(0); } // Use child indent if it's absolute and the child is contained on new line. @@ -287,6 +297,15 @@ public abstract class AbstractBlockWrapper { } } + /** + * Allows to answer if current wrapped block has a child block that is located before given block and has line feed. + * + * @param child target child block to process + * @return true if current block has a child that is located before the given block and contains line feed; + * false otherwise + */ + protected abstract boolean indentAlreadyUsedBefore(final AbstractBlockWrapper child); + /** * Allows to retrieve object that encapsulates information about number of symbols before the current block starting * from the line start. I.e. all symbols (either white space or not) between start of the line where current block begins diff --git a/platform/lang-impl/src/com/intellij/formatting/CompositeBlockWrapper.java b/platform/lang-impl/src/com/intellij/formatting/CompositeBlockWrapper.java index aaec1d4902b1..dca827b624f4 100644 --- a/platform/lang-impl/src/com/intellij/formatting/CompositeBlockWrapper.java +++ b/platform/lang-impl/src/com/intellij/formatting/CompositeBlockWrapper.java @@ -57,6 +57,15 @@ public class CompositeBlockWrapper extends AbstractBlockWrapper{ } } + @Override + protected boolean indentAlreadyUsedBefore(final AbstractBlockWrapper child) { + for (AbstractBlockWrapper childBefore : myChildren) { + if (childBefore == child) return false; + if (childBefore.getWhiteSpace().containsLineFeeds()) return true; + } + return false; + } + @Override protected IndentData getNumberOfSymbolsBeforeBlock() { if (myChildren == null || myChildren.isEmpty()) { diff --git a/platform/lang-impl/src/com/intellij/formatting/LeafBlockWrapper.java b/platform/lang-impl/src/com/intellij/formatting/LeafBlockWrapper.java index 4ee2f339dc46..99b38484192a 100644 --- a/platform/lang-impl/src/com/intellij/formatting/LeafBlockWrapper.java +++ b/platform/lang-impl/src/com/intellij/formatting/LeafBlockWrapper.java @@ -126,6 +126,11 @@ class LeafBlockWrapper extends AbstractBlockWrapper { myNextBlock = nextBlock; } + @Override + protected boolean indentAlreadyUsedBefore(final AbstractBlockWrapper child) { + return false; + } + @Override protected IndentData getNumberOfSymbolsBeforeBlock() { int spaces = getWhiteSpace().getSpaces(); diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java b/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java index 849cf1acc0ca..e00dd14a854a 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java @@ -269,17 +269,22 @@ public final class ProjectViewImpl extends ProjectView implements PersistentStat private void constructUi() { myActionGroupPanel = new JPanel(new BorderLayout()); - myLabel = new JLabel("View as:"); - if (!SystemInfo.isMac) { // See IDEADEV-41315 + myLabel = SystemInfo.isMac ? null : new JLabel("View as:"); + if (myLabel != null && !SystemInfo.isMac) { // See IDEADEV-41315 myLabel.setDisplayedMnemonic('a'); } + myCombo = new ComboBox(); myCombo.setBorder(BorderFactory.createEmptyBorder(0, 4, 0, 0)); - myLabel.setLabelFor(myCombo); final JPanel combo = new JPanel(new BorderLayout()); combo.setBorder(new EmptyBorder(4, 4, 4, 4)); - combo.add(myLabel, BorderLayout.WEST); + + if(myLabel != null) { + myLabel.setLabelFor(myCombo); + combo.add(myLabel, BorderLayout.WEST); + } + combo.add(myCombo, BorderLayout.CENTER); @@ -655,11 +660,11 @@ public final class ProjectViewImpl extends ProjectView implements PersistentStat }; private void installLabelFocusListener() { - myLabel.addFocusListener(myLabelFocusListener); + if (myLabel != null) myLabel.addFocusListener(myLabelFocusListener); } private void removeLabelFocusListener() { - myLabel.removeFocusListener(myLabelFocusListener); + if (myLabel != null) myLabel.removeFocusListener(myLabelFocusListener); } private boolean viewSelectionChanged() { diff --git a/platform/lang-impl/src/com/intellij/ide/util/DeleteHandler.java b/platform/lang-impl/src/com/intellij/ide/util/DeleteHandler.java index a458b57396e3..99c6273904e2 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/DeleteHandler.java +++ b/platform/lang-impl/src/com/intellij/ide/util/DeleteHandler.java @@ -31,6 +31,7 @@ import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.ex.MessagesEx; import com.intellij.openapi.vfs.VirtualFile; @@ -112,10 +113,10 @@ public class DeleteHandler { if (safeDeleteApplicable && !dumb) { DeleteDialog dialog = new DeleteDialog(project, elements, new DeleteDialog.Callback() { public void run(final DeleteDialog dialog) { - if (!CommonRefactoringUtil.checkReadOnlyStatusRecursively(project, Arrays.asList(elements))) return; + if (!CommonRefactoringUtil.checkReadOnlyStatusRecursively(project, Arrays.asList(elements), true)) return; SafeDeleteProcessor.createInstance(project, new Runnable() { public void run() { - dialog.close(DeleteDialog.CANCEL_EXIT_CODE); + dialog.close(DialogWrapper.CANCEL_EXIT_CODE); } }, elements, dialog.isSearchInComments(), dialog.isSearchInNonJava(), true).run(); } @@ -174,7 +175,7 @@ public class DeleteHandler { ArrayList readOnlyFiles = new ArrayList(); getReadOnlyVirtualFiles(virtualFile, readOnlyFiles, ftManager); - if (readOnlyFiles.size() > 0) { + if (!readOnlyFiles.isEmpty()) { int _result = Messages.showYesNoDialog(project, IdeBundle.message("prompt.directory.contains.read.only.files", virtualFile.getPresentableUrl()), IdeBundle.message("title.delete"), Messages.getQuestionIcon()); diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/resolve/reference/ReferenceProvidersRegistry.java b/platform/lang-impl/src/com/intellij/psi/impl/source/resolve/reference/ReferenceProvidersRegistry.java index 4c803fa08d3c..5147240cf015 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/resolve/reference/ReferenceProvidersRegistry.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/resolve/reference/ReferenceProvidersRegistry.java @@ -121,20 +121,17 @@ public class ReferenceProvidersRegistry extends PsiReferenceRegistrar { final PsiNamePatternCondition nameCondition = ContainerUtil.findInstance(pattern.getCondition().getConditions(), PsiNamePatternCondition.class); if (nameCondition != null) { - final ValuePatternCondition valueCondition = - ContainerUtil.findInstance(nameCondition.getNamePattern().getCondition().getConditions(), ValuePatternCondition.class); - if (valueCondition != null) { - final Collection strings = valueCondition.getValues(); - registerNamedReferenceProvider(ArrayUtil.toStringArray(strings), nameCondition, scope, true, provider, priority, pattern); - return; - } - - final CaseInsensitiveValuePatternCondition ciCondition = - ContainerUtil - .findInstance(nameCondition.getNamePattern().getCondition().getConditions(), CaseInsensitiveValuePatternCondition.class); - if (ciCondition != null) { - registerNamedReferenceProvider(ciCondition.getValues(), nameCondition, scope, false, provider, priority, pattern); - return; + for (PatternCondition condition : nameCondition.getNamePattern().getCondition().getConditions()) { + if (condition instanceof ValuePatternCondition) { + final Collection strings = ((ValuePatternCondition)condition).getValues(); + registerNamedReferenceProvider(ArrayUtil.toStringArray(strings), nameCondition, scope, true, provider, priority, pattern); + return; + } + if (condition instanceof CaseInsensitiveValuePatternCondition) { + final String[] strings = ((CaseInsensitiveValuePatternCondition)condition).getValues(); + registerNamedReferenceProvider(strings, nameCondition, scope, false, provider, priority, pattern); + return; + } } } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReference.java b/platform/lang-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReference.java index 0778acf2efb6..7a1a1ad63a57 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReference.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReference.java @@ -16,8 +16,6 @@ package com.intellij.psi.impl.source.resolve.reference.impl.providers; -import com.intellij.codeInsight.completion.CompletionProcess; -import com.intellij.codeInsight.completion.CompletionService; import com.intellij.codeInsight.daemon.EmptyResolveMessageProvider; import com.intellij.codeInsight.daemon.QuickFixProvider; import com.intellij.codeInsight.daemon.impl.HighlightInfo; @@ -238,12 +236,6 @@ public class FileReference implements FileReferenceOwner, PsiPolyVariantReferenc @NotNull public Object[] getVariants() { - final CompletionProcess process = CompletionService.getCompletionService().getCurrentCompletion(); - if (process != null && process.isAutopopupCompletion() && isSoft()) { - return ArrayUtil.EMPTY_OBJECT_ARRAY; - } - - final String s = getText(); if (s != null && s.equals("/")) { return ArrayUtil.EMPTY_OBJECT_ARRAY; diff --git a/platform/lang-impl/src/com/intellij/refactoring/BaseRefactoringProcessor.java b/platform/lang-impl/src/com/intellij/refactoring/BaseRefactoringProcessor.java index a5670b2e26b8..d8c4d996c419 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/BaseRefactoringProcessor.java +++ b/platform/lang-impl/src/com/intellij/refactoring/BaseRefactoringProcessor.java @@ -149,7 +149,7 @@ public abstract class BaseRefactoringProcessor { final Ref refUsages = new Ref(); final Ref refErrorLanguage = new Ref(); final Ref refProcessCanceled = new Ref(); - final Ref dumbModeOccured = new Ref(); + final Ref dumbModeOccurred = new Ref(); final Runnable findUsagesRunnable = new Runnable() { public void run() { @@ -163,7 +163,7 @@ public abstract class BaseRefactoringProcessor { refProcessCanceled.set(Boolean.TRUE); } catch (IndexNotReadyException e) { - dumbModeOccured.set(Boolean.TRUE); + dumbModeOccurred.set(Boolean.TRUE); } } }; @@ -176,13 +176,12 @@ public abstract class BaseRefactoringProcessor { Messages.showErrorDialog(myProject, RefactoringBundle.message("unsupported.refs.found", refErrorLanguage.get().getDisplayName()), RefactoringBundle.message("error.title")); return; } - if (!dumbModeOccured.isNull()) { + if (!dumbModeOccurred.isNull()) { DumbService.getInstance(myProject).showDumbModeNotification("Usage search is not available until indices are ready"); return; } if (!refProcessCanceled.isNull()) { - Messages.showErrorDialog(myProject, "Index corruption detected. Please retry the refactoring - indexes will be rebuilt automatically", - RefactoringBundle.message("error.title")); + Messages.showErrorDialog(myProject, "Index corruption detected. Please retry the refactoring - indexes will be rebuilt automatically", RefactoringBundle.message("error.title")); return; } diff --git a/platform/lang-impl/src/com/intellij/refactoring/inline/GenericInlineHandler.java b/platform/lang-impl/src/com/intellij/refactoring/inline/GenericInlineHandler.java index 875bee27ff72..207d28df1ae1 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/inline/GenericInlineHandler.java +++ b/platform/lang-impl/src/com/intellij/refactoring/inline/GenericInlineHandler.java @@ -119,7 +119,7 @@ public class GenericInlineHandler { elements.add(element); } - if (!CommonRefactoringUtil.checkReadOnlyStatusRecursively(project, elements)) { + if (!CommonRefactoringUtil.checkReadOnlyStatusRecursively(project, elements, true)) { return true; } ApplicationManager.getApplication().runWriteAction(new Runnable() { diff --git a/platform/lang-impl/src/com/intellij/refactoring/safeDelete/SafeDeleteHandler.java b/platform/lang-impl/src/com/intellij/refactoring/safeDelete/SafeDeleteHandler.java index 190ba8e8c501..2f3f3db0ff6c 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/safeDelete/SafeDeleteHandler.java +++ b/platform/lang-impl/src/com/intellij/refactoring/safeDelete/SafeDeleteHandler.java @@ -96,7 +96,7 @@ public class SafeDeleteHandler implements RefactoringActionHandler { ContainerUtil.addAll(fullElementsSet, temptoDelete); } - if (!CommonRefactoringUtil.checkReadOnlyStatusRecursively(project, fullElementsSet)) return; + if (!CommonRefactoringUtil.checkReadOnlyStatusRecursively(project, fullElementsSet, true)) return; final PsiElement[] elementsToDelete = PsiUtilBase.toPsiElementArray(fullElementsSet); diff --git a/platform/lang-impl/testSrc/com/intellij/formatting/BulkChangesMergerTest.java b/platform/lang-impl/testSrc/com/intellij/formatting/BulkChangesMergerTest.java index 34cfbd154679..36b46eb302ec 100644 --- a/platform/lang-impl/testSrc/com/intellij/formatting/BulkChangesMergerTest.java +++ b/platform/lang-impl/testSrc/com/intellij/formatting/BulkChangesMergerTest.java @@ -116,6 +116,12 @@ public class BulkChangesMergerTest { public void insufficientLengthForInplaceMerge() { doTest("0123", "", c("", 1, 3), c("abc", 4)); } + + @Config(inplace = true) + @Test + public void overlapWithPositiveGroupOnStart() { + doTest("0123456789ABC", "0abc1358d9eBC", c("abc", 1), c("", 2, 3), c("", 4, 5), c("", 6, 8), c("d", 9), c("e", 10, 11)); + } private static TextChangeImpl c(String text, int offset) { return c(text, offset, offset); diff --git a/platform/lvcs-impl/src/com/intellij/history/integration/ui/actions/LocalHistoryAction.java b/platform/lvcs-impl/src/com/intellij/history/integration/ui/actions/LocalHistoryAction.java index c59d39a24186..65f1d9e824b1 100644 --- a/platform/lvcs-impl/src/com/intellij/history/integration/ui/actions/LocalHistoryAction.java +++ b/platform/lvcs-impl/src/com/intellij/history/integration/ui/actions/LocalHistoryAction.java @@ -33,7 +33,7 @@ public abstract class LocalHistoryAction extends AnAction implements DumbAware { @Override public void update(AnActionEvent e) { Presentation p = e.getPresentation(); - if (getProject(e) == null) { + if (getEventProject(e) == null) { p.setVisible(false); p.setEnabled(false); return; @@ -74,8 +74,4 @@ public abstract class LocalHistoryAction extends AnAction implements DumbAware { } return commonParent; } - - protected Project getProject(AnActionEvent e) { - return e.getData(PlatformDataKeys.PROJECT); - } } diff --git a/platform/lvcs-impl/src/com/intellij/history/integration/ui/actions/LocalHistoryActionWithDialog.java b/platform/lvcs-impl/src/com/intellij/history/integration/ui/actions/LocalHistoryActionWithDialog.java index 094401debfaf..c35bec135947 100644 --- a/platform/lvcs-impl/src/com/intellij/history/integration/ui/actions/LocalHistoryActionWithDialog.java +++ b/platform/lvcs-impl/src/com/intellij/history/integration/ui/actions/LocalHistoryActionWithDialog.java @@ -24,7 +24,7 @@ import com.intellij.openapi.vfs.VirtualFile; public abstract class LocalHistoryActionWithDialog extends LocalHistoryAction { @Override public void actionPerformed(AnActionEvent e) { - showDialog(getProject(e), getGateway(), getFile(e), e); + showDialog(getEventProject(e), getGateway(), getFile(e), e); } protected abstract void showDialog(Project p, IdeaGateway gw, VirtualFile f, AnActionEvent e); diff --git a/platform/lvcs-impl/src/com/intellij/history/integration/ui/actions/RecentChangesAction.java b/platform/lvcs-impl/src/com/intellij/history/integration/ui/actions/RecentChangesAction.java index a7ac09e7ab39..b478f1bea934 100644 --- a/platform/lvcs-impl/src/com/intellij/history/integration/ui/actions/RecentChangesAction.java +++ b/platform/lvcs-impl/src/com/intellij/history/integration/ui/actions/RecentChangesAction.java @@ -22,6 +22,6 @@ import com.intellij.openapi.actionSystem.AnActionEvent; public class RecentChangesAction extends LocalHistoryAction { @Override public void actionPerformed(AnActionEvent e) { - new RecentChangesPopup(getProject(e), getGateway(), getVcs()).show(); + new RecentChangesPopup(getEventProject(e), getGateway(), getVcs()).show(); } } diff --git a/platform/platform-api/src/com/intellij/ide/diff/DiffElement.java b/platform/platform-api/src/com/intellij/ide/diff/DiffElement.java index f06fe968c3d1..8ac5383a20bc 100644 --- a/platform/platform-api/src/com/intellij/ide/diff/DiffElement.java +++ b/platform/platform-api/src/com/intellij/ide/diff/DiffElement.java @@ -24,18 +24,22 @@ import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.encoding.EncodingManager; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; import java.io.IOException; +import java.nio.charset.Charset; /** * @author Konstantin Bulenkov */ public abstract class DiffElement { + public static final DiffElement[] EMPTY_ARRAY = new DiffElement[0]; private DiffPanel myDiffPanel; private Editor myEditor; @@ -54,7 +58,7 @@ public abstract class DiffElement { public abstract boolean isContainer(); - public abstract DiffElement[] getChildren(); + public abstract DiffElement[] getChildren() throws IOException; @Nullable public abstract DiffElement findFileByRelativePath(String path); @@ -67,6 +71,10 @@ public abstract class DiffElement { @Nullable public abstract byte[] getContent() throws IOException; + public Charset getCharset() { + return EncodingManager.getInstance().getDefaultCharset(); + } + @Nullable public JComponent getViewComponent(Project project) { disposeViewComponent(); @@ -76,7 +84,7 @@ public abstract class DiffElement { final EditorFactory editorFactory = EditorFactory.getInstance(); final Document document = value instanceof VirtualFile ? FileDocumentManager.getInstance().getDocument((VirtualFile)value) - : editorFactory.createDocument(new String(content)); + : editorFactory.createDocument(StringUtil.convertLineSeparators(new String(content))); if (document != null && getFileType() != null) { myEditor = editorFactory.createEditor(document, project, getFileType(), true); myEditor.getSettings().setFoldingOutlineShown(false); @@ -97,6 +105,8 @@ public abstract class DiffElement { myDiffPanel = DiffManager.getInstance().createDiffPanel(parentWindow, project); myDiffPanel.setRequestFocus(false); myDiffPanel.setDiffRequest(request); + myDiffPanel.setTitle1(getName()); + myDiffPanel.setTitle2(element.getName()); return myDiffPanel.getComponent(); } @@ -126,7 +136,7 @@ public abstract class DiffElement { @Nullable protected DiffContent createDiffContent() { try { - return new SimpleContent(new String(getContent()), getFileType()); + return new SimpleContent(new String(getContent(), getCharset()), getFileType()); } catch (IOException e) {// } @@ -148,4 +158,13 @@ public abstract class DiffElement { myDiffPanel = null; } } + + public String getSeparator() { + return "/"; + } + + @Nullable + public Icon getIcon() { + return null; + } } diff --git a/java/execution/openapi/src/com/intellij/execution/filters/RmiStackFrameFilter.java b/platform/platform-api/src/com/intellij/ide/diff/DirDiffSettings.java similarity index 59% rename from java/execution/openapi/src/com/intellij/execution/filters/RmiStackFrameFilter.java rename to platform/platform-api/src/com/intellij/ide/diff/DirDiffSettings.java index 878b911b26f8..53c74b076c95 100644 --- a/java/execution/openapi/src/com/intellij/execution/filters/RmiStackFrameFilter.java +++ b/platform/platform-api/src/com/intellij/ide/diff/DirDiffSettings.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * 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. @@ -13,16 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.execution.filters; +package com.intellij.ide.diff; /** - * @author Gregory.Shrago + * @author Konstantin Bulenkov */ -public class RmiStackFrameFilter extends StackFrameFilter { - public boolean isAuxiliaryFrame(String className, String methodName) { - if (className.startsWith("java.rmi.") && methodName.startsWith("invoke")) { - return true; - } - return className.startsWith("sun.rmi."); - } -} \ No newline at end of file +public class DirDiffSettings { + public boolean showSize = true; + public boolean showDate = true; + + public boolean showEqual = false; + public boolean showDifferent = true; + public boolean showNewOnSource = true; + public boolean showNewOnTarget = true; +} diff --git a/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java b/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java index 3453c92d5016..7af773067a1d 100644 --- a/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java +++ b/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java @@ -3736,7 +3736,7 @@ public class AbstractTreeUi { final Set getSelectedElements() { final TreePath[] paths = myTree.getSelectionPaths(); - Set result = new HashSet(); + Set result = new LinkedHashSet(); if (paths != null) { for (TreePath eachPath : paths) { if (eachPath.getLastPathComponent() instanceof DefaultMutableTreeNode) { diff --git a/platform/platform-api/src/com/intellij/openapi/actionSystem/AnAction.java b/platform/platform-api/src/com/intellij/openapi/actionSystem/AnAction.java index bbcea138302f..7ca22d912bd8 100644 --- a/platform/platform-api/src/com/intellij/openapi/actionSystem/AnAction.java +++ b/platform/platform-api/src/com/intellij/openapi/actionSystem/AnAction.java @@ -18,10 +18,12 @@ package com.intellij.openapi.actionSystem; import com.intellij.openapi.Disposable; import com.intellij.openapi.keymap.KeymapUtil; import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.util.ArrayList; @@ -302,4 +304,9 @@ public abstract class AnAction { public interface TransparentUpdate { } + + @Nullable + public static Project getEventProject(AnActionEvent e) { + return e == null ? null : e.getData(PlatformDataKeys.PROJECT); + } } diff --git a/platform/platform-api/src/com/intellij/ui/ColorChooser.java b/platform/platform-api/src/com/intellij/ui/ColorChooser.java index a82749c87f9b..032b80104f77 100644 --- a/platform/platform-api/src/com/intellij/ui/ColorChooser.java +++ b/platform/platform-api/src/com/intellij/ui/ColorChooser.java @@ -15,6 +15,8 @@ */ package com.intellij.ui; +import org.jetbrains.annotations.Nullable; + import javax.swing.*; import java.awt.*; import java.lang.reflect.Field; @@ -27,7 +29,7 @@ import java.lang.reflect.Field; public class ColorChooser { private ColorChooser() {} - public static Color chooseColor(Component parent, String caption, Color preselectedColor) { + public static Color chooseColor(Component parent, String caption, @Nullable Color preselectedColor) { Color c = JColorChooser.showDialog(parent, caption, preselectedColor); try { // JColorChooser.ColorChooserDialog.cancelButton static field leaks parent dialogs thus finally Project. sigh... @@ -51,8 +53,6 @@ public class ColorChooser { catch (Exception e) { // Do nothing. Something changed in JColorChooser so we've failed to avoid memory leak in worst case. } - finally { - return c; - } + return c; } } diff --git a/platform/platform-api/src/com/intellij/ui/components/editors/JBComboBoxTableCellEditorComponent.java b/platform/platform-api/src/com/intellij/ui/components/editors/JBComboBoxTableCellEditorComponent.java index f14561de9384..5ba558f748fc 100644 --- a/platform/platform-api/src/com/intellij/ui/components/editors/JBComboBoxTableCellEditorComponent.java +++ b/platform/platform-api/src/com/intellij/ui/components/editors/JBComboBoxTableCellEditorComponent.java @@ -42,18 +42,32 @@ public class JBComboBoxTableCellEditorComponent extends JBLabel { private Object myValue; private ListCellRenderer myRenderer = new DefaultListCellRenderer() { - private Icon myCheckIcon = Icons.CHECK_ICON; - private Icon myEmptyIcon = EmptyIcon.create(Icons.CHECK_ICON.getIconWidth()); + public Icon myEmptyIcon; + @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { final JLabel label = (JLabel)super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); if (value == myValue) { - label.setIcon(myCheckIcon); + label.setIcon(getIcon(isSelected)); } else { - label.setIcon(myEmptyIcon); + label.setIcon(getEmptyIcon()); } return label; } + + private Icon getEmptyIcon() { + if (myEmptyIcon == null) { + myEmptyIcon = EmptyIcon.create(getIcon(true).getIconWidth()); + } + return myEmptyIcon; + } + + private Icon getIcon(boolean selected) { + final boolean small = "small".equals(JBComboBoxTableCellEditorComponent.this.getClientProperty("JComponent.sizeVariant")); + return small + ? selected ? Icons.CHECK_ICON_SMALL_SELECTED : Icons.CHECK_ICON_SMALL + : selected ? Icons.CHECK_ICON_SELECTED : Icons.CHECK_ICON; + } }; public JBComboBoxTableCellEditorComponent() { diff --git a/platform/platform-api/src/com/intellij/ui/switcher/ApplySwitchAction.java b/platform/platform-api/src/com/intellij/ui/switcher/ApplySwitchAction.java index c96de3a16e4d..f9ab352448b1 100644 --- a/platform/platform-api/src/com/intellij/ui/switcher/ApplySwitchAction.java +++ b/platform/platform-api/src/com/intellij/ui/switcher/ApplySwitchAction.java @@ -26,7 +26,7 @@ public class ApplySwitchAction extends AnAction { @Override public void update(AnActionEvent e) { - Project project = getProject(e); + Project project = getEventProject(e); if (project == null) { e.getPresentation().setEnabled(false); return; @@ -48,13 +48,10 @@ public class ApplySwitchAction extends AnAction { } } - private static Project getProject(AnActionEvent e) { - return PlatformDataKeys.PROJECT.getData(e.getDataContext()); - } @Override public void actionPerformed(AnActionEvent e) { - Project project = getProject(e); + Project project = getEventProject(e); SwitchManager switchManager = SwitchManager.getInstance(project); if (switchManager.canApplySwitch()) { diff --git a/platform/platform-api/src/com/intellij/util/Icons.java b/platform/platform-api/src/com/intellij/util/Icons.java index a7777e5a8357..92e2da2c473c 100644 --- a/platform/platform-api/src/com/intellij/util/Icons.java +++ b/platform/platform-api/src/com/intellij/util/Icons.java @@ -110,6 +110,9 @@ public abstract class Icons { public static final Icon SYNCHRONIZE_ICON = IconLoader.getIcon("/actions/sync.png"); public static final Icon CHECK_ICON = IconLoader.getIcon("/actions/checked.png"); + public static final Icon CHECK_ICON_SELECTED = IconLoader.getIcon("/actions/checked_selected.png"); + public static final Icon CHECK_ICON_SMALL = IconLoader.getIcon("/actions/checked_small.png"); + public static final Icon CHECK_ICON_SMALL_SELECTED = IconLoader.getIcon("/actions/checked_small_selected.png"); public static final Icon OPEN_EDIT_DIALOG_ICON = IconLoader.getIcon("/actions/showViewer.png"); public static final Icon FLATTEN_PACKAGES_ICON = IconLoader.getIcon("/objectBrowser/flattenPackages.png"); diff --git a/platform/platform-impl/src/com/intellij/featureStatistics/actions/ShowFeatureUsageStatisticsAction.java b/platform/platform-impl/src/com/intellij/featureStatistics/actions/ShowFeatureUsageStatisticsAction.java index 411441284f4b..2352f3487f0b 100644 --- a/platform/platform-impl/src/com/intellij/featureStatistics/actions/ShowFeatureUsageStatisticsAction.java +++ b/platform/platform-impl/src/com/intellij/featureStatistics/actions/ShowFeatureUsageStatisticsAction.java @@ -23,15 +23,11 @@ import com.intellij.openapi.project.DumbAware; public class ShowFeatureUsageStatisticsAction extends AnAction implements DumbAware { public void actionPerformed(AnActionEvent e) { - new ShowFeatureUsageStatisticsDialog(getProject(e)).show(); + new ShowFeatureUsageStatisticsDialog(getEventProject(e)).show(); } public void update(AnActionEvent e) { super.update(e); - e.getPresentation().setEnabled(getProject(e) != null); - } - - private Project getProject(AnActionEvent e) { - return PlatformDataKeys.PROJECT.getData(e.getDataContext()); + e.getPresentation().setEnabled(getEventProject(e) != null); } } \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/ide/actions/ShowSettingsAction.java b/platform/platform-impl/src/com/intellij/ide/actions/ShowSettingsAction.java index 2f17c493787e..c08a10578675 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/ShowSettingsAction.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/ShowSettingsAction.java @@ -15,6 +15,7 @@ */ package com.intellij.ide.actions; +import com.intellij.openapi.actionSystem.ActionPlaces; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.PlatformDataKeys; @@ -26,10 +27,19 @@ import com.intellij.openapi.options.ex.ProjectConfigurablesGroup; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; +import com.intellij.openapi.util.SystemInfo; import javax.swing.*; public class ShowSettingsAction extends AnAction implements DumbAware { + @Override + public void update(AnActionEvent e) { + if (SystemInfo.isMac && e.getPlace().equals(ActionPlaces.MAIN_MENU)) { + // It's called from Preferences in App menu. + e.getPresentation().setVisible(false); + } + } + public void actionPerformed(AnActionEvent e) { Project project = PlatformDataKeys.PROJECT.getData(e.getDataContext()); if (project == null) { diff --git a/platform/platform-impl/src/com/intellij/ide/startup/impl/StartupManagerImpl.java b/platform/platform-impl/src/com/intellij/ide/startup/impl/StartupManagerImpl.java index 73ce114153d3..efbad4ccb6d0 100644 --- a/platform/platform-impl/src/com/intellij/ide/startup/impl/StartupManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/ide/startup/impl/StartupManagerImpl.java @@ -117,7 +117,6 @@ public class StartupManagerImpl extends StartupManagerEx { myStartupActivitiesRunning = false; - startCacheUpdate(); myStartupActivitiesPassed = true; } finally { @@ -170,9 +169,9 @@ public class StartupManagerImpl extends StartupManagerEx { Registry.get("ide.firstStartup").setValue(false); } - private void startCacheUpdate() { + public void startCacheUpdate() { try { - DumbServiceImpl.getInstance(myProject).queueCacheUpdate(myCacheUpdaters); + DumbServiceImpl.getInstance(myProject).queueCacheUpdateInDumbMode(myCacheUpdaters); } catch (ProcessCanceledException e) { throw e; diff --git a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java index a878e19483cc..d679cecbe8db 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java @@ -486,7 +486,12 @@ public class ApplicationImpl extends ComponentManagerImpl implements Application ExtensionPoint point = Extensions.getRootArea().getExtensionPoint("com.intellij.ApplicationLoadListener"); final ApplicationLoadListener[] objects = point.getExtensions(); for (ApplicationLoadListener object : objects) { - object.beforeApplicationLoaded(this); + try { + object.beforeApplicationLoaded(this); + } + catch(Exception e) { + LOG.error(e); + } } } diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/DirDiffManager.java b/platform/platform-impl/src/com/intellij/openapi/diff/DirDiffManager.java index ad8c1361a1f1..6a7fc044dfb5 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/DirDiffManager.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/DirDiffManager.java @@ -16,6 +16,7 @@ package com.intellij.openapi.diff; import com.intellij.ide.diff.DiffElement; +import com.intellij.ide.diff.DirDiffSettings; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.project.Project; import org.jetbrains.annotations.NotNull; @@ -28,7 +29,7 @@ public abstract class DirDiffManager { return ServiceManager.getService(project, DirDiffManager.class); } - public abstract void showDiff(@NotNull DiffElement dir1, @NotNull DiffElement dir2); + public abstract void showDiff(@NotNull DiffElement dir1, @NotNull DiffElement dir2, DirDiffSettings settings); public abstract boolean canShow(@NotNull DiffElement dir1, @NotNull DiffElement dir2); } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/ex/util/EditorUtil.java b/platform/platform-impl/src/com/intellij/openapi/editor/ex/util/EditorUtil.java index 3e023d3a7f85..0bcaa23b1886 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/ex/util/EditorUtil.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/ex/util/EditorUtil.java @@ -349,7 +349,7 @@ public class EditorUtil { return calcColumnNumber(editor, text, start, offset, getTabSize(editor)); } - public static int calcColumnNumber(Editor editor, CharSequence text, int start, int offset, int tabSize) { + public static int calcColumnNumber(Editor editor, CharSequence text, final int start, final int offset, final int tabSize) { boolean useOptimization = true; if (editor != null) { SoftWrap softWrap = editor.getSoftWrapModel().getSoftWrap(start); @@ -375,8 +375,8 @@ public class EditorUtil { for (int i = start; i < offset; i++) { char c = text.charAt(i); assert c != '\n' && c != '\r' : - String.format("Symbol: %c, its index: %d, given start: %d, given offset: %d, given tab size: %d, text: '%s'", - c, i, start, offset, tabSize, text); + String.format("Symbol: %c, its index: %d, given start: %d, given offset: %d, given tab size: %d, document info: %s%ntext: '%s'", + c, i, start, offset, tabSize, editor.getDocument(), text); if (c == '\t') { shift += getTabLength(i + shift - start, tabSize) - 1; } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/BulkChangesMerger.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/BulkChangesMerger.java index a23ad662b501..49c056bc5f42 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/BulkChangesMerger.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/BulkChangesMerger.java @@ -15,6 +15,7 @@ */ package com.intellij.openapi.editor.impl; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.TextChange; import org.jetbrains.annotations.NotNull; @@ -33,6 +34,7 @@ import java.util.List; public class BulkChangesMerger { public static final BulkChangesMerger INSTANCE = new BulkChangesMerger(); + private static final Logger LOG = Logger.getInstance("#" + BulkChangesMerger.class.getName()); /** * Merges given changes within the given text and returns result as a new char sequence. @@ -105,7 +107,7 @@ public class BulkChangesMerger { throws IllegalArgumentException { // Consider two corner cases: - // 1. Every given change increase text length, i.e. change text length is more than changed region length. We can calculate + // 1. Every given change increases text length, i.e. change text length is more than changed region length. We can calculate // resulting text length and start merging the changes from the right end then; // 2. Every given change reduces text length, start from the left end then; // The general idea is to group all of the given changes by 'add text'/ 'remove text' criteria and process them sequentially. @@ -118,7 +120,7 @@ public class BulkChangesMerger { // 6) replace one symbol by three (diff +2); // Algorithm: // 1. Define the first group of change. First change diff is '+3', hence, iterate all changes until the resulting diff becomes - // equal or less to the zero. So, the first four changes conduct the first group. Initial change increased text length, hence, + // less or equal to the zero. So, the first four changes conduct the first group. Initial change increased text length, hence, // we process the changes from right to left starting at offset '4-th change start + 1'; // 2. Current diff is '-2' (4-th change diff is '-3' and one slot was necessary for previous group completion), so, that means // that we should process the 4-th and 5-th changes as the second group. Initial change direction is negative, hence, we @@ -138,12 +140,22 @@ public class BulkChangesMerger { + "minimum size: %d", data.length, length + diff )); } - - for (Context context = new Context(changes, data, length, length + diff); !context.isComplete();) { - if (!context.startGroup()) { - return; + + try { + for (Context context = new Context(changes, data, length, length + diff); !context.isComplete();) { + if (!context.startGroup()) { + return; + } + context.endGroup(); } - context.endGroup(); + } + catch (RuntimeException e) { + LOG.error(String.format( + "Invalid attempt to perform in-place document changes merge detected. Initial text length: %d, changes: %s, " + + "changes diff: %d, initial text: '%s'", length, changes, diff, Arrays.toString(data) + ), e); + char[] merged = mergeToCharArray(data, length, changes); + System.arraycopy(merged, 0, data, 0, length + diff); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretModelImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretModelImpl.java index 91d6c9fb3ab1..b82c5b4c67f4 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretModelImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretModelImpl.java @@ -182,7 +182,10 @@ public class CaretModelImpl implements CaretModel, PrioritizedDocumentListener, validateCallContext(); moveToLogicalPosition(myEditor.offsetToLogicalPosition(offset), locateBeforeSoftWrap); if (!myEditor.offsetToLogicalPosition(myOffset).equals(myEditor.offsetToLogicalPosition(offset))) { - LOG.error("caret moved to wrong offset. Requested:" + offset + " but actual:" + myOffset); + LOG.error( + "caret moved to wrong offset. Requested:" + offset + " but actual:" + myOffset + + ". Soft wraps data: " + myEditor.getSoftWrapModel() + ", folding data: " + myEditor.getFoldingModel() + + ", document:\n" + myEditor.getDocument().getText()); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java index 39f446ac2b6b..b74905633d47 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java @@ -784,6 +784,16 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx { } } + @Override + public String toString() { + StringBuilder buffer = new StringBuilder(); + int linesNumber = getLineCount(); + for (int i = 0; i < linesNumber; i++) { + buffer.append(i).append(": ").append(getLineStartOffset(i)).append("-").append(getLineEndOffset(i)).append("\n"); + } + return super.toString(); + } + private static class MyCharArray extends CharArray { public MyCharArray() { super(0); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java index 9ab0234dfe3a..808e82f69904 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java @@ -306,7 +306,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi int start = highlighter.getAffectedAreaStartOffset(); int end = highlighter.getAffectedAreaEndOffset(); int startLine = myDocument.getLineNumber(start); - int endLine = myDocument.getLineNumber(end); + int endLine = end < myDocument.getTextLength() ? myDocument.getLineNumber(end) : myDocument.getLineCount() - 1; repaintLines(Math.max(0, startLine - 1), Math.min(endLine + 1, getDocument().getLineCount())); ((EditorMarkupModelImpl)getMarkupModel()).markDirtied(); ((EditorMarkupModelImpl)getMarkupModel()).repaint(start, end); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldingModelImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldingModelImpl.java index 061242bced1e..8d12d6f0143b 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldingModelImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldingModelImpl.java @@ -38,6 +38,7 @@ import com.intellij.openapi.editor.ex.PrioritizedDocumentListener; import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.util.containers.MultiMap; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.awt.*; import java.util.Arrays; @@ -219,6 +220,7 @@ public class FoldingModelImpl implements FoldingModelEx, PrioritizedDocumentList return myFoldTree.fetchAllRegions(); } + @Nullable public FoldRegion getCollapsedRegionAtOffset(int offset) { return myFoldTree.fetchOutermost(offset); } @@ -227,6 +229,7 @@ public class FoldingModelImpl implements FoldingModelEx, PrioritizedDocumentList return myFoldTree.getLastTopLevelIndexBefore(offset); } + @Nullable public FoldRegion getFoldingPlaceholderAt(Point p) { assertReadAccess(); LogicalPosition pos = myEditor.xyToLogicalPosition(p); @@ -410,10 +413,12 @@ public class FoldingModelImpl implements FoldingModelEx, PrioritizedDocumentList return myFoldTree.getFoldedLinesCountBefore(offset); } + @Nullable public FoldRegion[] fetchTopLevel() { return myFoldTree.fetchTopLevel(); } + @Nullable public FoldRegion fetchOutermost(int offset) { return myFoldTree.fetchOutermost(offset); } @@ -478,4 +483,9 @@ public class FoldingModelImpl implements FoldingModelEx, PrioritizedDocumentList listener.onFoldRegionStateChange(foldRegion); } } + + @Override + public String toString() { + return Arrays.toString(myFoldTree.fetchTopLevel()); + } } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/SoftWrapModelImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/SoftWrapModelImpl.java index a048f2cf7cc0..1ed621d490a9 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/SoftWrapModelImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/SoftWrapModelImpl.java @@ -654,6 +654,11 @@ public class SoftWrapModelImpl implements SoftWrapModelEx, PrioritizedDocumentLi } } + @Override + public String toString() { + return myDataMapper.toString(); + } + /** * Defines generic interface for the command that may be proceeded in both 'soft wraps aware' and * 'soft wraps unaware' modes. diff --git a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java index f56995801a68..23de8bec50d7 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java @@ -391,7 +391,9 @@ public class ProjectManagerImpl extends ProjectManagerEx implements NamedJDOMExt notifyProjectOpenFailed(); return false; } - + + startupManager.startCacheUpdate(); + startupManager.runPostStartupActivities(); if (!ApplicationManager.getApplication().isHeadlessEnvironment() && !ApplicationManager.getApplication().isUnitTestMode()) { diff --git a/platform/platform-impl/src/com/intellij/ui/mac/MacFileChooserDialogImpl.java b/platform/platform-impl/src/com/intellij/ui/mac/MacFileChooserDialogImpl.java index effadf8b1a61..7cd2a4feeb34 100644 --- a/platform/platform-impl/src/com/intellij/ui/mac/MacFileChooserDialogImpl.java +++ b/platform/platform-impl/src/com/intellij/ui/mac/MacFileChooserDialogImpl.java @@ -54,7 +54,7 @@ public class MacFileChooserDialogImpl implements MacFileChooserDialog { public boolean callback(ID self, String selector, ID panel, ID filename) { if (filename == null || filename.intValue() == 0) return false; final String fileName = Foundation.toStringViaUTF8(filename); - final VirtualFile virtualFile = LocalFileSystem.getInstance().findFileByPath(fileName); + final VirtualFile virtualFile = LocalFileSystem.getInstance().refreshAndFindFileByPath(fileName); return virtualFile != null && (virtualFile.isDirectory() || getDescriptor().isFileSelectable(virtualFile)); } }; @@ -63,7 +63,7 @@ public class MacFileChooserDialogImpl implements MacFileChooserDialog { public boolean callback(ID self, String selector, ID panel, ID filename) { if (filename == null || filename.intValue() == 0) return false; final String fileName = Foundation.toStringViaUTF8(filename); - final VirtualFile virtualFile = LocalFileSystem.getInstance().findFileByPath(fileName); + final VirtualFile virtualFile = LocalFileSystem.getInstance().refreshAndFindFileByPath(fileName); return virtualFile != null && (!virtualFile.isDirectory() || getDescriptor().isFileSelectable(virtualFile)); } }; diff --git a/platform/platform-resources-en/src/messages/CodeInsightBundle.properties b/platform/platform-resources-en/src/messages/CodeInsightBundle.properties index 4185d953bb3b..80b26d17b51e 100644 --- a/platform/platform-resources-en/src/messages/CodeInsightBundle.properties +++ b/platform/platform-resources-en/src/messages/CodeInsightBundle.properties @@ -444,7 +444,6 @@ intentions.category.ejb=EJB set.language.level=Set language level set.language.level.to.0=Set language level to {0} remove.annotation=Remove annotation -add.external.annotation.test=Add external annotation @{0} deannotate.intention.action.text=Deannotate deannotate.intention.chooser.title=Choose annotation to delete javadoc.type.parameters=Type parameters: diff --git a/platform/platform-resources-en/src/messages/XDebuggerBundle.properties b/platform/platform-resources-en/src/messages/XDebuggerBundle.properties index 1a348fb16065..3d8a4ddef3a1 100644 --- a/platform/platform-resources-en/src/messages/XDebuggerBundle.properties +++ b/platform/platform-resources-en/src/messages/XDebuggerBundle.properties @@ -2,6 +2,9 @@ xdebugger.colors.page.name=Debugger debugger.configurable.display.name=Debugger +xdebugger.default.content.title=Debug +xdebugger.debugger.tab.title=Debugger + xdebugger.remove.line.breakpoint.action.text=Remove xdebugger.disable.breakpoint.action.text=Disable xdebugger.enable.breakpoint.action.text=Enable diff --git a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml index 05a5f7cca9d1..6e15798e5d84 100644 --- a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml @@ -200,6 +200,8 @@ + + @@ -311,6 +313,7 @@ + diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml index b74d5e3e7830..266312e61dee 100644 --- a/platform/platform-resources/src/META-INF/LangExtensions.xml +++ b/platform/platform-resources/src/META-INF/LangExtensions.xml @@ -396,10 +396,6 @@ - - - - diff --git a/platform/platform-resources/src/META-INF/XmlPlugin.xml b/platform/platform-resources/src/META-INF/XmlPlugin.xml index f7c41a14e2b6..dab28f21f1c0 100644 --- a/platform/platform-resources/src/META-INF/XmlPlugin.xml +++ b/platform/platform-resources/src/META-INF/XmlPlugin.xml @@ -45,6 +45,8 @@ + + diff --git a/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java b/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java index 635712957238..ebaec0f6a621 100644 --- a/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java @@ -300,7 +300,9 @@ public abstract class LightPlatformTestCase extends UsefulTestCase implements Da }); - ((StartupManagerImpl)StartupManager.getInstance(ourProject)).runStartupActivities(); + final StartupManagerImpl startupManager = (StartupManagerImpl)StartupManager.getInstance(ourProject); + startupManager.runStartupActivities(); + startupManager.startCacheUpdate(); } }.execute().throwException(); } diff --git a/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java b/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java index 53c481f95d52..20a8b74833ee 100644 --- a/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java @@ -234,8 +234,10 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro } protected void runStartupActivities() { - ((StartupManagerImpl)StartupManager.getInstance(myProject)).runStartupActivities(); - ((StartupManagerImpl)StartupManager.getInstance(myProject)).runPostStartupActivities(); + final StartupManagerImpl startupManager = (StartupManagerImpl)StartupManager.getInstance(myProject); + startupManager.runStartupActivities(); + startupManager.startCacheUpdate(); + startupManager.runPostStartupActivities(); } protected File getIprFile() throws IOException { @@ -448,6 +450,7 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro mm.projectOpened(); setUpJdk(); sm.runStartupActivities(); + sm.startCacheUpdate(); // extra init for libraries sm.runPostStartupActivities(); } diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/HeavyIdeaTestFixtureImpl.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/HeavyIdeaTestFixtureImpl.java index fa619fa3e76d..ede3db26db1b 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/HeavyIdeaTestFixtureImpl.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/HeavyIdeaTestFixtureImpl.java @@ -157,6 +157,7 @@ class HeavyIdeaTestFixtureImpl extends BaseFixture implements HeavyIdeaTestFixtu StartupManagerImpl sm = (StartupManagerImpl)StartupManager.getInstance(myProject); sm.runStartupActivities(); + sm.startCacheUpdate(); sm.runPostStartupActivities(); ProjectManagerEx.getInstanceEx().setCurrentTestProject(myProject); diff --git a/platform/util/src/com/intellij/openapi/util/BuildNumber.java b/platform/util/src/com/intellij/openapi/util/BuildNumber.java index d5a3fa065412..ec19e8cadb85 100644 --- a/platform/util/src/com/intellij/openapi/util/BuildNumber.java +++ b/platform/util/src/com/intellij/openapi/util/BuildNumber.java @@ -83,7 +83,9 @@ public class BuildNumber implements Comparable { int buildNumber; if (baselineVersionSeparator > 0) { try { - baselineVersion = Integer.parseInt(code.substring(0, baselineVersionSeparator)); + final String baselineVersionString = code.substring(0, baselineVersionSeparator); + if (baselineVersionString.isEmpty()) return null; + baselineVersion = Integer.parseInt(baselineVersionString); code = code.substring(baselineVersionSeparator + 1); } catch (NumberFormatException e) { diff --git a/platform/vcs-impl/src/com/intellij/ide/actions/SynchronizeCurrentFileAction.java b/platform/vcs-impl/src/com/intellij/ide/actions/SynchronizeCurrentFileAction.java index c7037855449d..cf2a07db23af 100644 --- a/platform/vcs-impl/src/com/intellij/ide/actions/SynchronizeCurrentFileAction.java +++ b/platform/vcs-impl/src/com/intellij/ide/actions/SynchronizeCurrentFileAction.java @@ -30,7 +30,7 @@ public class SynchronizeCurrentFileAction extends AnAction implements DumbAware public void update(AnActionEvent e) { VirtualFile[] files = getFiles(e); - if (getProject(e) == null || files == null || files.length == 0) { + if (getEventProject(e) == null || files == null || files.length == 0) { e.getPresentation().setEnabled(false); return; } @@ -48,7 +48,7 @@ public class SynchronizeCurrentFileAction extends AnAction implements DumbAware } public void actionPerformed(AnActionEvent e) { - final Project project = getProject(e); + final Project project = getEventProject(e); final VirtualFile[] files = getFiles(e); ApplicationManager.getApplication().runWriteAction(new Runnable() { @@ -73,10 +73,6 @@ public class SynchronizeCurrentFileAction extends AnAction implements DumbAware WindowManager.getInstance().getStatusBar(project).setInfo(message); } - private static Project getProject(AnActionEvent e) { - return e.getData(PlatformDataKeys.PROJECT); - } - private static VirtualFile[] getFiles(AnActionEvent e) { return e.getData(PlatformDataKeys.VIRTUAL_FILE_ARRAY); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffDialog.java b/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffDialog.java index 80242e511937..c75e55e6772b 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffDialog.java +++ b/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffDialog.java @@ -15,8 +15,10 @@ */ package com.intellij.openapi.diff.impl.dir; +import com.intellij.ide.diff.DirDiffSettings; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.ui.table.JBTable; import javax.swing.*; @@ -25,15 +27,21 @@ import javax.swing.*; */ public class DirDiffDialog extends DialogWrapper { private final DirDiffTableModel myModel; + private final DirDiffSettings mySettings; private DirDiffPanel myDiffPanel; - public DirDiffDialog(Project project, DirDiffTableModel model) { + public DirDiffDialog(Project project, DirDiffTableModel model, DirDiffSettings settings) { super(project); myModel = model; + mySettings = settings; setSize(600, 600); setTitle("Directory Diff"); init(); - myDiffPanel.getTable().changeSelection(myModel.getElementAt(0).isSeparator() ? 1: 0, 3, false, false); + final JBTable table = myDiffPanel.getTable(); + table.changeSelection(myModel.getElementAt(0).isSeparator() ? 1 : 0, 3, false, false); + table.setColumnSelectionAllowed(false); + table.getTableHeader().setReorderingAllowed(false); + table.getTableHeader().setResizingAllowed(false); } @Override @@ -43,7 +51,7 @@ public class DirDiffDialog extends DialogWrapper { @Override protected JComponent createCenterPanel() { - myDiffPanel = new DirDiffPanel(myModel, this); + myDiffPanel = new DirDiffPanel(myModel, this, mySettings); return myDiffPanel.getPanel(); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffElement.java b/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffElement.java index 28df55a7c9e4..7bd7e8545496 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffElement.java +++ b/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffElement.java @@ -19,6 +19,7 @@ import com.intellij.ide.diff.DiffElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import javax.swing.*; import java.sql.Date; import java.text.DateFormat; import java.text.SimpleDateFormat; @@ -150,4 +151,8 @@ public class DirDiffElement { } public static enum ElementType {SOURCE, TARGET, SEPARATOR, CHANGED} + + public Icon getIcon() { + return mySource != null ? mySource.getIcon() : myTarget.getIcon(); + } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffManagerImpl.java b/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffManagerImpl.java index 4ac2d4119cb0..65bfcb362a6c 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffManagerImpl.java +++ b/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffManagerImpl.java @@ -16,6 +16,7 @@ package com.intellij.openapi.diff.impl.dir; import com.intellij.ide.diff.DiffElement; +import com.intellij.ide.diff.DirDiffSettings; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diff.DirDiffManager; import com.intellij.openapi.progress.ProgressIndicator; @@ -23,7 +24,6 @@ import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; -import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; /** @@ -37,18 +37,18 @@ public class DirDiffManagerImpl extends DirDiffManager { } @Override - public void showDiff(@NotNull final DiffElement dir1, @NotNull final DiffElement dir2) { + public void showDiff(@NotNull final DiffElement dir1, @NotNull final DiffElement dir2, final DirDiffSettings settings) { Task.Backgroundable task = new Task.Backgroundable(myProject, "Directory comparison", true) { @Override public void run(@NotNull ProgressIndicator indicator) { indicator.setText("Calculating differences"); - final DirDiffTableModel model = new DirDiffTableModel(myProject, dir1, dir2, indicator); + final DirDiffTableModel model = new DirDiffTableModel(myProject, dir1, dir2, indicator, settings); final Runnable run = new Runnable() { public void run() { if (model.getRowCount() == 0) { Messages.showInfoMessage(myProject, "No difference has been found", "Directory Diff Tool"); } else { - new DirDiffDialog(myProject, model).show(); + new DirDiffDialog(myProject, model, settings).show(); } } }; diff --git a/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffPanel.java b/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffPanel.java index 3208d4a30ef3..8849338c9002 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffPanel.java +++ b/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffPanel.java @@ -16,6 +16,7 @@ package com.intellij.openapi.diff.impl.dir; import com.intellij.ide.diff.DiffElement; +import com.intellij.ide.diff.DirDiffSettings; import com.intellij.openapi.actionSystem.ActionManager; import com.intellij.openapi.actionSystem.ActionToolbar; import com.intellij.openapi.diff.impl.dir.actions.DirDiffToolbarActions; @@ -29,6 +30,7 @@ import javax.swing.*; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.table.TableColumn; +import javax.swing.table.TableColumnModel; import java.awt.*; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; @@ -56,7 +58,7 @@ public class DirDiffPanel { private JComponent myViewComponent; private DiffElement myCurrentElement; - public DirDiffPanel(DirDiffTableModel model, DirDiffDialog dirDiffDialog) { + public DirDiffPanel(DirDiffTableModel model, DirDiffDialog dirDiffDialog, DirDiffSettings settings) { myModel = model; myDialog = dirDiffDialog; mySourceDirField.setText(model.getSourceDir().getPath()); @@ -128,11 +130,12 @@ public class DirDiffPanel { } if (0 <= row && row < rows && !myModel.getElementAt(row).isSeparator()) { e.consume(); - myTable.changeSelection(row, 3, false, false); + myTable.changeSelection(row, (myModel.getColumnCount() - 1) / 2, false, false); } } }); - final TableColumn operationColumn = myTable.getColumnModel().getColumn(3); + final TableColumnModel columnModel = myTable.getColumnModel(); + final TableColumn operationColumn = columnModel.getColumn((columnModel.getColumnCount() - 1) / 2); operationColumn.setMaxWidth(25); operationColumn.setMinWidth(25); final ActionToolbar toolbar = ActionManager.getInstance().createActionToolbar("DirDiff", new DirDiffToolbarActions(myModel), true); diff --git a/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffTableCellRenderer.java b/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffTableCellRenderer.java index 2cb81f2ff76e..7eea4fc10f16 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffTableCellRenderer.java +++ b/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffTableCellRenderer.java @@ -76,26 +76,30 @@ public class DirDiffTableCellRenderer extends DefaultTableCellRenderer { if (hasFocus || isSelected) { label.setBorder(noFocusBorder); } + label.setIcon(null); final DirDiffOperation op = element.getOperation(); - if (column == 3) { + if (column == (table.getColumnCount() - 1) / 2) { label.setIcon(op.getIcon()); label.setHorizontalAlignment(CENTER); return label; - } else { - label.setIcon(null); } Color fg = isSelected ? UIUtil.getTableSelectionForeground() : getForegroundColor(op); label.setForeground(fg); - if (column == 2 || column == 4) { + final String name = table.getColumnName(column); + if (DirDiffTableModel.COLUMN_DATE.equals(name)) { label.setHorizontalAlignment(CENTER); - } else if (column == 1 || column == 5) { + } else if (DirDiffTableModel.COLUMN_SIZE.equals(name)) { label.setHorizontalAlignment(RIGHT); label.setText(label.getText() + " "); } else { label.setHorizontalAlignment(LEFT); - label.setText(" " + label.getText()); + final String text = label.getText(); + label.setText(" " + text); + if (text != null && text.trim().length() > 0) { + label.setIcon(element.getIcon()); + } } } return c; diff --git a/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffTableModel.java b/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffTableModel.java index 1eff7a6d7f9c..5c9cebd83e93 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffTableModel.java +++ b/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffTableModel.java @@ -16,6 +16,7 @@ package com.intellij.openapi.diff.impl.dir; import com.intellij.ide.diff.DiffElement; +import com.intellij.ide.diff.DirDiffSettings; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; import com.intellij.util.containers.HashSet; @@ -29,26 +30,32 @@ import java.util.*; * @author Konstantin Bulenkov */ public class DirDiffTableModel extends AbstractTableModel { + public static final String COLUMN_NAME = "Name"; + public static final String COLUMN_SIZE = "Size"; + public static final String COLUMN_DATE = "Date"; private final Project myProject; + private final DirDiffSettings mySettings; private DiffElement mySrc; + private HashMap mySrcPaths = new HashMap(); + private HashMap myTrgPaths = new HashMap(); private DiffElement myTrg; final List myElements = new ArrayList(); - private boolean showEqual = false; - private boolean showDifferent = true; - private boolean showNewOnSource = true; - private boolean showNewOnTarget = true; - public DirDiffTableModel(Project project, DiffElement src, DiffElement trg, ProgressIndicator indicator) { + public DirDiffTableModel(Project project, DiffElement src, DiffElement trg, ProgressIndicator indicator, DirDiffSettings settings) { myProject = project; + mySettings = settings; loadModel(src, trg, indicator); } public void loadModel(DiffElement src, DiffElement trg, ProgressIndicator indicator) { mySrc = src; myTrg = trg; + scan("", src, mySrcPaths, indicator, true); + scan("", trg, myTrgPaths, indicator, true); + final HashSet files = new HashSet(); - scan("", src, files, indicator, true); - scan("", trg, files, indicator, true); + files.addAll(mySrcPaths.keySet()); + files.addAll(myTrgPaths.keySet()); final ArrayList pathes = new ArrayList(files); Collections.sort(pathes, new Comparator() { @Override @@ -77,8 +84,8 @@ public class DirDiffTableModel extends AbstractTableModel { }); for (String path : pathes) { - final DiffElement srcFile = src.findFileByRelativePath(path); - final DiffElement trgFile = trg.findFileByRelativePath(path); + final DiffElement srcFile = mySrcPaths.get(path); + final DiffElement trgFile = myTrgPaths.get(path); if (srcFile == null && trgFile != null) { myElements.add(DirDiffElement.createTargetOnly(trgFile)); } else if (srcFile != null && trgFile == null) { @@ -144,18 +151,23 @@ public class DirDiffTableModel extends AbstractTableModel { return myTrg; } - private static void scan(String prefix, DiffElement file, HashSet files, ProgressIndicator indicator, boolean isRoot) { + private static void scan(String prefix, DiffElement file, HashMap files, ProgressIndicator indicator, boolean isRoot) { if (file.isContainer()) { indicator.setText2(file.getPath()); String p = isRoot ? "" : prefix + file.getName() + "/"; if (!isRoot) { - files.add(p); + files.put(p, file); } - for (DiffElement f : file.getChildren()) { - scan(p, f, files, indicator, false); + try { + for (DiffElement f : file.getChildren()) { + scan(p, f, files, indicator, false); + } + } + catch (IOException e) { + //TODO: error message } } else { - files.add(prefix + file.getName()); + files.put(prefix + file.getName(), file); } } @@ -166,7 +178,10 @@ public class DirDiffTableModel extends AbstractTableModel { @Override public int getColumnCount() { - return 7; + int count = 3; + if (mySettings.showDate) count += 2; + if (mySettings.showSize) count += 2; + return count; } @Nullable @@ -176,25 +191,30 @@ public class DirDiffTableModel extends AbstractTableModel { if (element.isSeparator()) { return columnIndex == 0 ? element.getName() : null; } - switch (columnIndex) { - case 0: return element.getSourceName(); - case 1: return element.getSourceSize(); - case 2: return element.getSourceModificationDate(); - case 3: return ""; - case 4: return element.getTargetModificationDate(); - case 5: return element.getTargetSize(); - case 6: return element.getTargetName(); + + final String name = getColumnName(columnIndex); + boolean isSrc = columnIndex < getColumnCount() / 2; + if (name.equals(COLUMN_NAME)) { + return isSrc ? element.getSourceName() : element.getTargetName(); + } else if (name.equals(COLUMN_SIZE)) { + return isSrc ? element.getSourceSize() : element.getTargetSize(); + } else if (name.equals(COLUMN_DATE)) { + return isSrc ? element.getSourceModificationDate() : element.getTargetModificationDate(); } - return null; + return ""; } @Override public String getColumnName(int column) { + final int count = (getColumnCount() - 1) / 2; + if (column == count) return "*"; + if (column > count) { + column = getColumnCount() - 1 - column; + } switch (column) { - case 0: case 6: return "Name"; - case 1: case 5: return "Size"; - case 2: case 4: return "Date"; - case 3: return "*"; + case 0: return COLUMN_NAME; + case 1: return mySettings.showSize ? COLUMN_SIZE : COLUMN_DATE; + case 2: return COLUMN_DATE; } return ""; } @@ -204,34 +224,34 @@ public class DirDiffTableModel extends AbstractTableModel { } public boolean isShowEqual() { - return showEqual; + return mySettings.showEqual; } public void setShowEqual(boolean show) { - this.showEqual = show; + mySettings.showEqual = show; } public boolean isShowDifferent() { - return showDifferent; + return mySettings.showDifferent; } public void setShowDifferent(boolean show) { - this.showDifferent = show; + mySettings.showDifferent = show; } public boolean isShowNewOnSource() { - return showNewOnSource; + return mySettings.showNewOnSource; } public void setShowNewOnSource(boolean show) { - this.showNewOnSource = show; + mySettings.showNewOnSource = show; } public boolean isShowNewOnTarget() { - return showNewOnTarget; + return mySettings.showNewOnTarget; } public void setShowNewOnTarget(boolean show) { - this.showNewOnTarget = show; + mySettings.showNewOnTarget = show; } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/TestDirDiffAction.java b/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/TestDirDiffAction.java index 76c3c07b64de..92112bc1043b 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/TestDirDiffAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/TestDirDiffAction.java @@ -16,6 +16,7 @@ package com.intellij.openapi.diff.impl.dir; import com.intellij.ide.diff.DiffElement; +import com.intellij.ide.diff.DirDiffSettings; import com.intellij.ide.diff.VirtualFileDiffElement; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; @@ -46,7 +47,7 @@ public class TestDirDiffAction extends AnAction { DiffElement elem2 = new VirtualFileDiffElement(files2[0]); final DirDiffManager diffManager = DirDiffManager.getInstance(project); if (diffManager.canShow(elem1, elem2)) { - diffManager.showDiff(elem1, elem2); + diffManager.showDiff(elem1, elem2, new DirDiffSettings()); } } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/DocumentWrapper.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/DocumentWrapper.java index c74188166afe..bf71a2ffee7c 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/DocumentWrapper.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/DocumentWrapper.java @@ -55,7 +55,11 @@ public class DocumentWrapper { } private String getLine(final int i) { - return myDocument.getText(new TextRange(myDocument.getLineStartOffset(i), myDocument.getLineEndOffset(i))); + TextRange range = new TextRange(myDocument.getLineStartOffset(i), myDocument.getLineEndOffset(i)); + if (range.getLength() < 0) { + assert false : myDocument; + } + return myDocument.getText(range); } } diff --git a/platform/xdebugger-api/src/com/intellij/xdebugger/XDebugProcess.java b/platform/xdebugger-api/src/com/intellij/xdebugger/XDebugProcess.java index 514bb10bc0e6..9a2079acb9b4 100644 --- a/platform/xdebugger-api/src/com/intellij/xdebugger/XDebugProcess.java +++ b/platform/xdebugger-api/src/com/intellij/xdebugger/XDebugProcess.java @@ -22,7 +22,6 @@ import com.intellij.execution.process.ProcessHandler; import com.intellij.execution.ui.ExecutionConsole; import com.intellij.execution.ui.RunnerLayoutUi; import com.intellij.openapi.actionSystem.DefaultActionGroup; -import com.intellij.openapi.util.Ref; import com.intellij.xdebugger.breakpoints.XBreakpointHandler; import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider; import com.intellij.xdebugger.stepping.XSmartStepIntoHandler; @@ -134,7 +133,7 @@ public abstract class XDebugProcess { /** * Check is it is possible to perform commands such as resume, step etc. And notify user if necessary - * @return true if process can actually perform user requests at this moment + * @return {@code true} if process can actually perform user requests at this moment */ public boolean checkCanPerformCommands() { return true; diff --git a/platform/xdebugger-api/src/com/intellij/xdebugger/XDebugSession.java b/platform/xdebugger-api/src/com/intellij/xdebugger/XDebugSession.java index 86453dbf60be..00b5143ce45a 100644 --- a/platform/xdebugger-api/src/com/intellij/xdebugger/XDebugSession.java +++ b/platform/xdebugger-api/src/com/intellij/xdebugger/XDebugSession.java @@ -19,6 +19,7 @@ package com.intellij.xdebugger; import com.intellij.execution.configurations.RunProfile; import com.intellij.execution.ui.ConsoleView; import com.intellij.execution.ui.RunContentDescriptor; +import com.intellij.execution.ui.RunnerLayoutUi; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.MessageType; import com.intellij.xdebugger.breakpoints.XBreakpoint; @@ -135,4 +136,6 @@ public interface XDebugSession extends AbstractDebuggerSession { void updateExecutionPosition(); ConsoleView getConsoleView(); + + RunnerLayoutUi getUI(); } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java index 14da42c4b621..ea8d0cfa129f 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java @@ -28,13 +28,13 @@ import com.intellij.execution.runners.ProgramRunner; import com.intellij.execution.ui.ConsoleView; import com.intellij.execution.ui.ConsoleViewContentType; import com.intellij.execution.ui.RunContentDescriptor; +import com.intellij.execution.ui.RunnerLayoutUi; import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.application.Result; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.ToolWindowId; import com.intellij.openapi.wm.ToolWindowManager; @@ -51,6 +51,7 @@ import com.intellij.xdebugger.impl.evaluate.quick.common.ValueLookupManager; import com.intellij.xdebugger.impl.ui.DebuggerUIUtil; import com.intellij.xdebugger.impl.ui.XDebugSessionData; import com.intellij.xdebugger.impl.ui.XDebugSessionTab; +import com.intellij.xdebugger.impl.ui.XDebuggerUIConstants; import com.intellij.xdebugger.stepping.XSmartStepIntoHandler; import com.intellij.xdebugger.stepping.XSmartStepIntoVariant; import org.jetbrains.annotations.NotNull; @@ -217,6 +218,11 @@ public class XDebugSessionImpl implements XDebugSession { return mySessionTab; } + @Override + public RunnerLayoutUi getUI() { + return mySessionTab.getUi(); + } + private void initSessionTab() { mySessionTab = new XDebugSessionTab(myProject, mySessionName); if (myEnvironment != null) { @@ -408,6 +414,12 @@ public class XDebugSessionImpl implements XDebugSession { myCurrentStackFrame = null; myCurrentPosition = null; myPaused = false; + UIUtil.invokeLaterIfNeeded(new Runnable() { + @Override + public void run() { + mySessionTab.getUi().clearAttractionBy(XDebuggerUIConstants.LAYOUT_VIEW_BREAKPOINT_CONDITION); + } + }); myDispatcher.getMulticaster().sessionResumed(); } @@ -574,6 +586,7 @@ public class XDebugSessionImpl implements XDebugSession { showSessionTab(); } mySessionTab.toFront(); + mySessionTab.getUi().attractBy(XDebuggerUIConstants.LAYOUT_VIEW_BREAKPOINT_CONDITION); } }); myDispatcher.getMulticaster().sessionPaused(); diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerUtilImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerUtilImpl.java index 2f79a7efdcbd..d5094a6f6b8a 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerUtilImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerUtilImpl.java @@ -209,6 +209,8 @@ public class XDebuggerUtilImpl extends XDebuggerUtil { public void iterateLine(@NotNull Project project, @NotNull Document document, int line, @NotNull Processor processor) { PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(document); + if (file == null) return; + int lineStart; int lineEnd; diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XLineBreakpointImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XLineBreakpointImpl.java index a6fc5cf3da55..d4bfd1db5096 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XLineBreakpointImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XLineBreakpointImpl.java @@ -429,7 +429,7 @@ public class XLineBreakpointImpl

extends XBreak } public void actionPerformed(final AnActionEvent e) { - XDebuggerUtil.getInstance().removeBreakpoint(getProject(), XLineBreakpointImpl.this); + XDebuggerUtil.getInstance().removeBreakpoint(XLineBreakpointImpl.this.getProject(), XLineBreakpointImpl.this); } } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java index 3f2b06d4a977..d96830595c0b 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java @@ -29,6 +29,8 @@ import com.intellij.execution.ui.ExecutionConsole; import com.intellij.execution.ui.RunContentDescriptor; import com.intellij.execution.ui.RunnerLayoutUi; import com.intellij.execution.ui.actions.CloseAction; +import com.intellij.execution.ui.layout.LayoutAttractionPolicy; +import com.intellij.execution.ui.layout.LayoutViewOptions; import com.intellij.execution.ui.layout.PlaceInGrid; import com.intellij.ide.CommonActionsManager; import com.intellij.ide.actions.ContextHelpAction; @@ -68,7 +70,10 @@ public class XDebugSessionTab extends DebuggerSessionTabBase { mySessionName = sessionName; myUi = RunnerLayoutUi.Factory.getInstance(project).create("Debug", "unknown!", sessionName, this); - myUi.getDefaults().initTabDefaults(0, "Debug", null); + myUi.getDefaults() + .initTabDefaults(0, XDebuggerBundle.message("xdebugger.debugger.tab.title"), null) + .initFocusContent(DebuggerContentInfo.FRAME_CONTENT, XDebuggerUIConstants.LAYOUT_VIEW_BREAKPOINT_CONDITION) + .initFocusContent(DebuggerContentInfo.CONSOLE_CONTENT, LayoutViewOptions.STARTUP, new LayoutAttractionPolicy.FocusOnce(false)); } private static ActionGroup getActionGroup(final String id) { @@ -201,71 +206,6 @@ public class XDebugSessionTab extends DebuggerSessionTabBase { return myRunContentDescriptor; } - private RunContentDescriptor initUI(final @NotNull XDebugSession session, final @NotNull XDebugSessionData sessionData, - final @Nullable ExecutionEnvironment environment, - final @Nullable ProgramRunner runner, - ConsoleView consoleView) { - final XDebugProcess debugProcess = session.getDebugProcess(); - ProcessHandler processHandler = debugProcess.getProcessHandler(); - myConsole = consoleView; - myRunContentDescriptor = new RunContentDescriptor(myConsole, processHandler, myUi.getComponent(), mySessionName); - - myUi.addContent(createFramesContent(session), 0, PlaceInGrid.left, false); - myUi.addContent(createVariablesContent(session), 0, PlaceInGrid.center, false); - myUi.addContent(createWatchesContent(session, sessionData), 0, PlaceInGrid.right, false); - final Content consoleContent = createConsoleContent(); - myUi.addContent(consoleContent, 1, PlaceInGrid.bottom, false); - attachNotificationTo(consoleContent); - - session.getDebugProcess().registerAdditionalContent(myUi); - RunContentBuilder.addAdditionalConsoleEditorActions(myConsole, consoleContent); - myUi.addContent(consoleContent, 0, PlaceInGrid.bottom, false); - - if (ApplicationManager.getApplication().isUnitTestMode()) { - return myRunContentDescriptor; - } - - DefaultActionGroup leftToolbar = new DefaultActionGroup(); - final Executor executor = DefaultDebugExecutor.getDebugExecutorInstance(); - if (runner != null && environment != null) { - RestartAction restartAction = new RestartAction(executor, runner, myRunContentDescriptor.getProcessHandler(), XDebuggerUIConstants.DEBUG_AGAIN_ICON, - myRunContentDescriptor, environment); - leftToolbar.add(restartAction); - restartAction.registerShortcut(myUi.getComponent()); - } - - leftToolbar.addAll(getActionGroup(XDebuggerActions.TOOL_WINDOW_LEFT_TOOLBAR_GROUP)); - - //group.addSeparator(); - //addAction(group, DebuggerActions.EXPORT_THREADS); - leftToolbar.addSeparator(); - - leftToolbar.add(myUi.getOptions().getLayoutActions()); - - leftToolbar.addSeparator(); - - leftToolbar.add(PinToolwindowTabAction.getPinAction()); - leftToolbar.add(new CloseAction(executor, myRunContentDescriptor, getProject())); - leftToolbar.add(new ContextHelpAction(executor.getHelpId())); - - DefaultActionGroup topToolbar = new DefaultActionGroup(); - topToolbar.addAll(getActionGroup(XDebuggerActions.TOOL_WINDOW_TOP_TOOLBAR_GROUP)); - - session.getDebugProcess().registerAdditionalActions(leftToolbar, topToolbar); - myUi.getOptions().setLeftToolbar(leftToolbar, ActionPlaces.DEBUGGER_TOOLBAR); - myUi.getOptions().setTopToolbar(topToolbar, ActionPlaces.DEBUGGER_TOOLBAR); - - if (environment != null) { - final RunProfile runConfiguration = environment.getRunProfile(); - registerFileMatcher(runConfiguration); - initLogConsoles(runConfiguration, myRunContentDescriptor.getProcessHandler()); - } - - rebuildViews(); - - return myRunContentDescriptor; - } - public RunnerLayoutUi getUi() { return myUi; } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerUIConstants.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerUIConstants.java index cdafa528aeea..d467eac7bea4 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerUIConstants.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebuggerUIConstants.java @@ -50,6 +50,7 @@ public class XDebuggerUIConstants { public static final Icon WATCHES_TAB_ICON = IconLoader.getIcon("/debugger/watches.png"); public static final Icon CONSOLE_TAB_ICON = IconLoader.getIcon("/debugger/console.png"); public static final SimpleTextAttributes TYPE_ATTRIBUTES = SimpleTextAttributes.GRAY_ATTRIBUTES; + public static final String LAYOUT_VIEW_BREAKPOINT_CONDITION = "breakpoint"; private XDebuggerUIConstants() { } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/ValueMarkerPresentationDialog.form b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/ValueMarkerPresentationDialog.form new file mode 100644 index 000000000000..1a09d3670a7a --- /dev/null +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/ValueMarkerPresentationDialog.form @@ -0,0 +1,61 @@ + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/ValueMarkerPresentationDialog.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/ValueMarkerPresentationDialog.java new file mode 100644 index 000000000000..57164045b3d8 --- /dev/null +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/ValueMarkerPresentationDialog.java @@ -0,0 +1,97 @@ +/* + * 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.xdebugger.impl.ui.tree; + +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.ui.FixedSizeButton; +import com.intellij.ui.ColorChooser; +import com.intellij.ui.DocumentAdapter; +import com.intellij.ui.SimpleColoredComponent; +import com.intellij.ui.SimpleTextAttributes; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import javax.swing.event.DocumentEvent; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/** + * @author nik + */ +public abstract class ValueMarkerPresentationDialog extends DialogWrapper { + private static final Color DEFAULT_COLOR = Color.RED; + private SimpleColoredComponent myColorSample; + private Color myColor; + private JPanel myMainPanel; + private JTextField myLabelField; + private FixedSizeButton myChooseColorButton; + private JPanel mySamplePanel; + + public ValueMarkerPresentationDialog(final @Nullable String defaultText) { + super(true); + setTitle("Select Object Label"); + setModal(true); + myLabelField.getDocument().addDocumentListener(new DocumentAdapter() { + protected void textChanged(final DocumentEvent e) { + updateLabelSample(); + } + }); + myChooseColorButton.addActionListener(new ActionListener() { + public void actionPerformed(final ActionEvent e) { + final Color color = ColorChooser.chooseColor(myColorSample, "Choose Label Color", myColor); + if (color != null) { + myColor = color; + updateLabelSample(); + } + } + }); + myColor = DEFAULT_COLOR; + if (defaultText != null) { + myLabelField.setText(defaultText.trim()); + updateLabelSample(); + } + } + + public JComponent getPreferredFocusedComponent() { + return myLabelField; + } + + @Override + protected JComponent createCenterPanel() { + return myMainPanel; + } + + private void updateLabelSample() { + myColorSample.clear(); + SimpleTextAttributes attributes = new SimpleTextAttributes(SimpleTextAttributes.STYLE_BOLD, myColor); + myColorSample.append(myLabelField.getText().trim(), attributes); + } + + @Nullable + public ValueMarkup getConfiguredMarkup() { + final String text = myLabelField.getText().trim(); + return text.isEmpty() ? null : new ValueMarkup(text, myColor, null); + } + + private void createUIComponents() { + myColorSample = new SimpleColoredComponent(); + mySamplePanel = new JPanel(new BorderLayout()); + mySamplePanel.setBorder(BorderFactory.createEtchedBorder()); + mySamplePanel.add(BorderLayout.CENTER, myColorSample); + myChooseColorButton = new FixedSizeButton(mySamplePanel); + } +} diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/ValueMarkup.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/ValueMarkup.java similarity index 64% rename from java/debugger/impl/src/com/intellij/debugger/ui/tree/ValueMarkup.java rename to platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/ValueMarkup.java index ed4ec28f2b83..06a45c48b09b 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/tree/ValueMarkup.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/ValueMarkup.java @@ -13,11 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.debugger.ui.tree; +package com.intellij.xdebugger.impl.ui.tree; -import com.intellij.codeInsight.daemon.impl.HighlightInfoType; -import com.intellij.openapi.editor.colors.EditorColorsManager; -import com.intellij.openapi.editor.markup.TextAttributes; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -28,8 +25,6 @@ import java.awt.*; * Date: Jan 27, 2007 */ public class ValueMarkup { - public static final long AUTO_MARKUP_REFERRING_OBJECTS_LIMIT = 100L; // todo: some reasonable limit - private final String myText; private final Color myColor; @Nullable @@ -39,7 +34,7 @@ public class ValueMarkup { this(text, color, null); } - public ValueMarkup(final String text, final Color color, String toolTipText) { + public ValueMarkup(final String text, final Color color, @Nullable String toolTipText) { myText = text; myColor = color; myToolTipText = toolTipText; @@ -58,10 +53,4 @@ public class ValueMarkup { public String getToolTipText() { return myToolTipText; } - - public static Color getAutoMarkupColor() { - final EditorColorsManager manager = EditorColorsManager.getInstance(); - final TextAttributes textAttributes = manager.getGlobalScheme().getAttributes(HighlightInfoType.STATIC_FIELD.getAttributesKey()); - return textAttributes.getForegroundColor(); - } } diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/internationalization/StringConcatenationInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/internationalization/StringConcatenationInspection.java index 7ea12ec8ea63..986cd29af58a 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/internationalization/StringConcatenationInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/internationalization/StringConcatenationInspection.java @@ -88,9 +88,11 @@ public class StringConcatenationInspection extends BaseInspection { final PsiMethod method = PsiTreeUtil.getParentOfType(expressionParent, PsiMethod.class); + if (method != null) { final InspectionGadgetsFix fix = new DelegatingFix( new AddAnnotationFix(AnnotationUtil.NON_NLS, method)); result.add(fix); + } } return result.toArray(new InspectionGadgetsFix[result.size()]); } @@ -191,4 +193,4 @@ public class StringConcatenationInspection extends BaseInspection { registerError(sign, expression); } } -} \ No newline at end of file +} diff --git a/plugins/copyright/src/com/maddyhome/idea/copyright/psi/UpdateJavaFileCopyright.java b/plugins/copyright/src/com/maddyhome/idea/copyright/psi/UpdateJavaFileCopyright.java index 211eb5509f21..7a7ec803f769 100644 --- a/plugins/copyright/src/com/maddyhome/idea/copyright/psi/UpdateJavaFileCopyright.java +++ b/plugins/copyright/src/com/maddyhome/idea/copyright/psi/UpdateJavaFileCopyright.java @@ -24,7 +24,6 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.maddyhome.idea.copyright.CopyrightProfile; import com.maddyhome.idea.copyright.options.JavaOptions; -import com.maddyhome.idea.copyright.options.LanguageOptions; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; @@ -84,7 +83,7 @@ public class UpdateJavaFileCopyright extends UpdatePsiFileCopyright final List comments = new ArrayList(); collectComments(first, topclass, comments); collectComments(topclass.getFirstChild(), topclass.getModifierList(), comments); - checkComments(topclass.getModifierList(), location == JavaOptions.LOCATION_BEFORE_CLASS, comments); + checkCommentsForTopClass(topclass, location, comments); } else if (location == JavaOptions.LOCATION_BEFORE_CLASS) { @@ -92,6 +91,10 @@ public class UpdateJavaFileCopyright extends UpdatePsiFileCopyright } } + protected void checkCommentsForTopClass(PsiClass topclass, int location, List comments) { + checkComments(topclass.getModifierList(), location == JavaOptions.LOCATION_BEFORE_CLASS, comments); + } + @Nullable protected PsiElement[] getImportsList() { final PsiJavaFile javaFile = (PsiJavaFile)getFile(); diff --git a/plugins/generate-tostring/src/org/jetbrains/generate/tostring/GenerateToStringWorker.java b/plugins/generate-tostring/src/org/jetbrains/generate/tostring/GenerateToStringWorker.java index fa5614ffc46e..e0871b8a29e5 100644 --- a/plugins/generate-tostring/src/org/jetbrains/generate/tostring/GenerateToStringWorker.java +++ b/plugins/generate-tostring/src/org/jetbrains/generate/tostring/GenerateToStringWorker.java @@ -33,6 +33,7 @@ import com.intellij.psi.javadoc.PsiDocComment; import com.intellij.util.IncorrectOperationException; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.VelocityEngine; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.generate.tostring.config.*; import org.jetbrains.generate.tostring.element.*; @@ -389,11 +390,11 @@ public class GenerateToStringWorker { PsiAdapterFactory.getPsiAdapter().executeCommand(clazz.getProject(), writeCommand); } - private static void annotate(final PsiMethod result, String fqn) throws IncorrectOperationException { + private static void annotate(@NotNull PsiMethod result, String fqn) throws IncorrectOperationException { Project project = result.getProject(); AddAnnotationFix fix = new AddAnnotationFix(fqn, result); if (fix.isAvailable(project, null, result.getContainingFile())) { fix.invoke(project, null, result.getContainingFile()); } } -} \ No newline at end of file +} diff --git a/plugins/git4idea/src/git4idea/Git.java b/plugins/git4idea/src/git4idea/Git.java new file mode 100644 index 000000000000..9d1c50133508 --- /dev/null +++ b/plugins/git4idea/src/git4idea/Git.java @@ -0,0 +1,44 @@ +/* + * 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 git4idea; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vcs.VcsException; +import com.intellij.openapi.vfs.VirtualFile; +import git4idea.commands.GitCommand; +import git4idea.commands.GitHandlerUtil; +import git4idea.commands.GitLineHandler; + +/** + * Low level layer of Git commands. + * + * @author Kirill Likhodedov + */ +public class Git { + + /** + * Calls 'git init' on the specified directory. + */ + public static void init(Project project, VirtualFile root) throws VcsException { + GitLineHandler h = new GitLineHandler(project, root, GitCommand.INIT); + h.setNoSSH(true); + GitHandlerUtil.runInCurrentThread(h, null); + if (!h.errors().isEmpty()) { + throw h.errors().get(0); + } + } + +} diff --git a/plugins/git4idea/src/git4idea/actions/GitInit.java b/plugins/git4idea/src/git4idea/actions/GitInit.java index b234fb22d740..ae31838a3d88 100644 --- a/plugins/git4idea/src/git4idea/actions/GitInit.java +++ b/plugins/git4idea/src/git4idea/actions/GitInit.java @@ -28,12 +28,11 @@ import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.ProjectLevelVcsManager; import com.intellij.openapi.vcs.VcsDirectoryMapping; +import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vfs.VirtualFile; +import git4idea.Git; import git4idea.GitUtil; import git4idea.GitVcs; -import git4idea.commands.GitCommand; -import git4idea.commands.GitHandlerUtil; -import git4idea.commands.GitLineHandler; import git4idea.i18n.GitBundle; import git4idea.ui.GitUIUtil; import org.jetbrains.annotations.NotNull; @@ -73,13 +72,14 @@ public class GitInit extends DumbAwareAction { return; } } - GitLineHandler h = new GitLineHandler(project, root, GitCommand.INIT); - h.setNoSSH(true); - GitHandlerUtil.doSynchronously(h, GitBundle.getString("initializing.title"), h.printableCommandLine()); - if (!h.errors().isEmpty()) { - GitUIUtil.showOperationErrors(project, h.errors(), "git init"); + + try { + Git.init(project, root); + } catch (VcsException ex) { + GitUIUtil.showOperationErrors(project, Collections.singleton(ex), "git init"); return; } + if (project.isDefault()) return; int rc = Messages.showYesNoDialog(project, GitBundle.getString("init.add.root.message"), GitBundle.getString("init.add.root.title"), Messages.getQuestionIcon()); diff --git a/plugins/git4idea/src/git4idea/checkout/GitCheckoutProvider.java b/plugins/git4idea/src/git4idea/checkout/GitCheckoutProvider.java index ee5fe42d0217..269e0c843a62 100644 --- a/plugins/git4idea/src/git4idea/checkout/GitCheckoutProvider.java +++ b/plugins/git4idea/src/git4idea/checkout/GitCheckoutProvider.java @@ -15,31 +15,39 @@ */ package git4idea.checkout; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; import com.intellij.openapi.vcs.CheckoutProvider; +import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; -import git4idea.GitVcs; +import com.intellij.vcsUtil.VcsUtil; +import git4idea.Git; import git4idea.actions.BasicAction; -import git4idea.commands.*; -import git4idea.config.GitVersion; +import git4idea.commands.GitCommand; +import git4idea.commands.GitSimpleHandler; import git4idea.i18n.GitBundle; import git4idea.ui.GitUIUtil; +import git4idea.update.GitFetcher; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; +import java.util.concurrent.atomic.AtomicBoolean; /** * Checkout provider for the Git */ public class GitCheckoutProvider implements CheckoutProvider { - /** - * The version number since which "-v" options is supported. - */ - // TODO check if they will actually support the switch in the released 1.6.0.5 - private static final GitVersion VERBOSE_CLONE_SUPPORTED = new GitVersion(1, 6, 0, 5); + + private static final Logger LOG = Logger.getInstance(GitCheckoutProvider.class); + + public String getVcsName() { + return "_Git"; + } public void doCheckout(@NotNull final Project project, @Nullable final Listener listener) { BasicAction.saveAll(); @@ -56,64 +64,110 @@ public class GitCheckoutProvider implements CheckoutProvider { final String sourceRepositoryURL = dialog.getSourceRepositoryURL(); final String directoryName = dialog.getDirectoryName(); final String parentDirectory = dialog.getParentDirectory(); - checkout(project, listener, destinationParent, sourceRepositoryURL, directoryName, parentDirectory); + clone(project, listener, destinationParent, sourceRepositoryURL, directoryName, parentDirectory); } - public static void checkout(final Project project, - final Listener listener, - final VirtualFile destinationParent, - final String sourceRepositoryURL, - final String directoryName, - final String parentDirectory) { - final GitLineHandler handler = getCloneHandler(project, sourceRepositoryURL, new File(parentDirectory), directoryName); - GitTask task = new GitTask(project, handler, GitBundle.message("cloning.repository", sourceRepositoryURL)); - task.setProgressAnalyzer(new GitStandardProgressAnalyzer()); - task.executeAsync(new GitTaskResultHandlerAdapter() { + public static void clone(final Project project, + final Listener listener, + final VirtualFile destinationParent, + final String sourceRepositoryURL, + final String directoryName, + final String parentDirectory) { + + final AtomicBoolean cloneResult = new AtomicBoolean(); + new Task.Backgroundable(project, GitBundle.message("cloning.repository", sourceRepositoryURL)) { + @Override + public void run(@NotNull ProgressIndicator indicator) { + cloneResult.set(doClone(indicator, project, directoryName, parentDirectory, sourceRepositoryURL)); + } + @Override public void onSuccess() { - destinationParent.refresh(true, true, new Runnable() { - public void run() { - if (project.isOpen() && (!project.isDisposed()) && (!project.isDefault())) { - final VcsDirtyScopeManager mgr = VcsDirtyScopeManager.getInstance(project); - mgr.fileDirty(destinationParent); - } + if (!cloneResult.get()) { + return; + } + + destinationParent.refresh(true, true, new Runnable() { + public void run() { + if (project.isOpen() && (!project.isDisposed()) && (!project.isDefault())) { + final VcsDirtyScopeManager mgr = VcsDirtyScopeManager.getInstance(project); + mgr.fileDirty(destinationParent); } - }); - listener.directoryCheckedOut(new File(parentDirectory, directoryName)); - listener.checkoutCompleted(); + } + }); + listener.directoryCheckedOut(new File(parentDirectory, directoryName)); + listener.checkoutCompleted(); } - - @Override - protected void onFailure() { - GitUIUtil.notifyGitErrors(project, "Couldn't clone", "Couldn't clone from " + sourceRepositoryURL, handler.errors()); - } - }); + }.queue(); } - /** - * {@inheritDoc} - */ - public String getVcsName() { - return "_Git"; + private static boolean doClone(ProgressIndicator indicator, Project project, String directoryName, String parentDirectory, String sourceRepositoryURL) { + final VirtualFile root = mkdir(project, directoryName, parentDirectory); + if (root == null) { return false; } + if (!init(project, root)) { return false; } + if (!addRemote(project, root, sourceRepositoryURL)) { return false; } + if (!fetch(project, root, indicator)) { return false; } + return checkout(project, root); } - /** - * Prepare clone handler - * - * @param project a project - * @param url an url - * @param directory a base directory - * @param name a name to checkout - * @param originName origin name (ignored if null or empty string) - * @return a handler for clone operation - */ - public static GitLineHandler getCloneHandler(Project project, final String url, final File directory, final String name) { - GitLineHandler handler = new GitLineHandler(project, directory, GitCommand.CLONE); - if (VERBOSE_CLONE_SUPPORTED.isOlderOrEqual(GitVcs.getInstance(project).getVersion())) { - handler.addParameters("-v"); + private static @Nullable VirtualFile mkdir(Project project, String directoryName, String parentDirectory) { + final File dir = new File(parentDirectory, directoryName); + if (dir.exists()) { + GitUIUtil.notifyError(project, "Couldn't clone", "Directory " + dir + " already exists."); + return null; } - handler.addParameters(url, name); - handler.addProgressParameter(); - return handler; + if (!dir.mkdir()) { + GitUIUtil.notifyError(project, "Couldn't clone", "Can't create directory " + dir + ""); + return null; + } + + return VcsUtil.getVirtualFileWithRefresh(dir); } + + private static boolean init(Project project, VirtualFile root) { + try { + Git.init(project, root); + } catch (VcsException e) { + LOG.info("init ", e); + GitUIUtil.notifyError(project, "Couldn't clone", "Couldn't git init in " + root.getPresentableUrl() + "", true, e); + return false; + } + return true; + } + + private static boolean addRemote(Project project, VirtualFile root, String remoteUrl) { + final GitSimpleHandler addRemoteHandler = new GitSimpleHandler(project, root, GitCommand.REMOTE); + addRemoteHandler.setNoSSH(true); + addRemoteHandler.addParameters("add", "origin", remoteUrl); + try { + addRemoteHandler.run(); + return true; + } + catch (VcsException e) { + LOG.info("addRemote ", e); + GitUIUtil.notifyError(project, "Couldn't clone", "Couldn't add remote " + remoteUrl + "", true, e); + return false; + } + } + + private static boolean fetch(Project project, VirtualFile root, ProgressIndicator indicator) { + return new GitFetcher(project, indicator).fetch(root); + } + + private static boolean checkout(Project project, VirtualFile root) { + GitSimpleHandler h = new GitSimpleHandler(project, root, GitCommand.CHECKOUT); + h.setNoSSH(true); + h.addParameters("-b", "master", "origin/master"); + try { + h.run(); + return true; + } + catch (VcsException e) { + LOG.info("checkout ", e); + GitUIUtil.notifyError(project, "Clone not completed", + "Couldn't checkout master branch.
All changes were fetched to " + root + ".", true, e); + return false; + } + } + } diff --git a/plugins/git4idea/src/git4idea/commands/GitHandlerUtil.java b/plugins/git4idea/src/git4idea/commands/GitHandlerUtil.java index 5b16c138a697..3e9acd911347 100644 --- a/plugins/git4idea/src/git4idea/commands/GitHandlerUtil.java +++ b/plugins/git4idea/src/git4idea/commands/GitHandlerUtil.java @@ -181,7 +181,7 @@ public class GitHandlerUtil { * @param handler a handler to run * @param postStartAction an action that is executed */ - static void runInCurrentThread(final GitHandler handler, @Nullable final Runnable postStartAction) { + public static void runInCurrentThread(final GitHandler handler, @Nullable final Runnable postStartAction) { handler.runInCurrentThread(postStartAction); } diff --git a/plugins/git4idea/src/git4idea/ui/GitUIUtil.java b/plugins/git4idea/src/git4idea/ui/GitUIUtil.java index 52a7ad517847..6f6c19331a20 100644 --- a/plugins/git4idea/src/git4idea/ui/GitUIUtil.java +++ b/plugins/git4idea/src/git4idea/ui/GitUIUtil.java @@ -72,7 +72,9 @@ public class GitUIUtil { } else { errorMessages = new HashSet(errors.size()); for (VcsException error : errors) { - errorMessages.addAll(Arrays.asList(error.getMessages())); + for (String message : error.getMessages()) { + errorMessages.add(message.replace("\n", "
")); + } } } notifyMessages(project, title, description, type, important, errorMessages); diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubCheckoutProvider.java b/plugins/github/src/org/jetbrains/plugins/github/GithubCheckoutProvider.java index 4efad1a01bfd..8ec8f7b1edc4 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubCheckoutProvider.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubCheckoutProvider.java @@ -109,7 +109,7 @@ public class GithubCheckoutProvider implements CheckoutProvider { final String repositoryName = name; final String repositoryOwner = owner; final String checkoutUrl = host + repositoryOwner + "/" + repositoryName + ".git"; - GitCheckoutProvider.checkout(project, listener, selectedPathFile, checkoutUrl, projectName, selectedPath); + GitCheckoutProvider.clone(project, listener, selectedPathFile, checkoutUrl, projectName, selectedPath); } @Override diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml index 6d7eb36e55f2..1692c19ad1b7 100644 --- a/plugins/groovy/src/META-INF/plugin.xml +++ b/plugins/groovy/src/META-INF/plugin.xml @@ -214,7 +214,6 @@ - diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyBundle.properties b/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyBundle.properties index 3f1095fbe9e6..45bd0072cacf 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyBundle.properties +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyBundle.properties @@ -347,3 +347,4 @@ groovy.file.extension.is.not.mapped.to.groovy.file.type=*.groovy files are mappe class.is.not.annotation=''{0}'' is not an annotation method.call.is.ambiguous=Method call is ambiguous duplicated.named.parameter=Duplicated named parameter ''{0}'' found +cannot.find.method.call=No signature of method: {0}.call() is applicable for {1} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/actions/ConvertToJavaAction.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/actions/ConvertToJavaAction.java index 93191c92549d..da3520067bcf 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/actions/ConvertToJavaAction.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/actions/ConvertToJavaAction.java @@ -24,7 +24,6 @@ import com.intellij.refactoring.RefactoringActionHandler; import com.intellij.refactoring.actions.BaseRefactoringAction; import org.jetbrains.plugins.groovy.GroovyFileType; import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; import org.jetbrains.plugins.groovy.refactoring.convertToJava.ConvertToJavaHandler; /** @@ -49,14 +48,11 @@ public class ConvertToJavaAction extends BaseRefactoringAction { @Override protected boolean isEnabledOnElements(PsiElement[] elements) { + for (PsiElement element : elements) { - if (element instanceof GrTypeDefinition) { final PsiFile containingFile = element.getContainingFile(); - if (containingFile instanceof GroovyFile && ((GroovyFile)containingFile).getClasses().length == 1) continue; + if (containingFile instanceof GroovyFile) continue; return false; - } - if (element instanceof GroovyFile) continue; - return false; } return true; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java index 1556dae9a4d3..40e7b5f4d997 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java @@ -372,8 +372,16 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { if (className == null) return null; final PsiMethod[] byName = clazz.findMethodsByName(className, true); if (byName.length == 0) return null; + Outer: for (PsiMethod method : byName) { if (method.getParameterList().getParametersCount() == 0) return method; + if (!(method instanceof GrMethod)) continue; + final GrParameter[] parameters = ((GrMethod)method).getParameterList().getParameters(); + + for (GrParameter parameter : parameters) { + if (!parameter.isOptional()) continue Outer; + } + return method; } return null; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyAssignabilityCheckInspection.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyAssignabilityCheckInspection.java index 36732f3c3ac6..abede067a4ad 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyAssignabilityCheckInspection.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyAssignabilityCheckInspection.java @@ -19,8 +19,6 @@ package org.jetbrains.plugins.groovy.codeInspection.assignment; import com.intellij.psi.*; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.TypeConversionUtil; -import com.intellij.util.containers.MultiMap; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -35,7 +33,6 @@ import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrConstructorInvocation; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentLabel; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; @@ -55,7 +52,6 @@ import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; -import java.util.Collection; import java.util.Map; /** @@ -328,57 +324,66 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { checkNamedArgumentsType(call); } - private void highlightInapplicableMethodUsage(GroovyResolveResult methodResolveResult, PsiElement place, - PsiMethod method, PsiType[] argumentTypes) { + private void highlightInapplicableMethodUsage(GroovyResolveResult methodResolveResult, + PsiElement place, + PsiMethod method, + PsiType[] argumentTypes) { + final PsiClass containingClass = method.getContainingClass(); + if (containingClass == null) { + registerCannotApplyError(place, argumentTypes, method.getName()); + return; + } + final String typesString = buildArgTypesList(argumentTypes); + final PsiElementFactory factory = JavaPsiFacade.getInstance(method.getProject()).getElementFactory(); + final PsiClassType containingType = factory.createType(containingClass, methodResolveResult.getSubstitutor()); + final String canonicalText = containingType.getInternalCanonicalText(); + String message = GroovyBundle.message("cannot.apply.method1", method.getName(), canonicalText, typesString); PsiElement elementToHighlight = PsiUtil.getArgumentsList(place); if (elementToHighlight == null || elementToHighlight.getTextRange().getLength() == 0) { elementToHighlight = place; } - - final String typesString = buildArgTypesList(argumentTypes); - String message; - final PsiClass containingClass = method.getContainingClass(); - if (containingClass != null) { - final PsiClassType containingType = JavaPsiFacade.getInstance(method.getProject()).getElementFactory() - .createType(containingClass, methodResolveResult.getSubstitutor()); - message = GroovyBundle.message("cannot.apply.method1", method.getName(), containingType.getInternalCanonicalText(), typesString); - } - else { - message = GroovyBundle.message("cannot.apply.method.or.closure", method.getName(), typesString); - } - registerError(elementToHighlight, message); } + private boolean checkCallApplicability(PsiType type, GroovyPsiElement place) { + + PsiType[] argumentTypes = PsiUtil.getArgumentTypes(place, true); if (type instanceof GrClosureType) { - PsiType[] argumentTypes = PsiUtil.getArgumentTypes(place, true); if (argumentTypes == null) return true; if (PsiUtil.isApplicable(argumentTypes, (GrClosureType)type, place)) return true; - final String typesString = buildArgTypesList(argumentTypes); - String message = GroovyBundle.message("cannot.apply.method.or.closure", place.getText(), typesString); - PsiElement elementToHighlight = PsiUtil.getArgumentsList(place); - if (elementToHighlight == null || elementToHighlight.getTextRange().getLength() == 0) elementToHighlight = place; - registerError(elementToHighlight, message); + registerCannotApplyError(place, argumentTypes, place.getText()); return false; } else if (type != null) { - final GroovyResolveResult[] calls = - ResolveUtil.getMethodCandidates(type, "call", place, PsiUtil.getArgumentTypes(place, true)); + final GroovyResolveResult[] calls = ResolveUtil.getMethodCandidates(type, "call", place, argumentTypes); for (GroovyResolveResult result : calls) { PsiElement resolved = result.getElement(); if (resolved instanceof PsiMethod) { if (!checkMethodApplicability(result, place)) return false; } + else if (resolved instanceof PsiField) { + if (!checkCallApplicability(((PsiField)resolved).getType(), place)) return false; + } + } + if (calls.length == 0) { + registerCannotApplyError(place, argumentTypes, place.getText()); } - return true; } return true; } + private void registerCannotApplyError(PsiElement place, PsiType[] argumentTypes, String invokedText) { + final String typesString = buildArgTypesList(argumentTypes); + String message = GroovyBundle.message("cannot.apply.method.or.closure", invokedText, typesString); + PsiElement elementToHighlight = PsiUtil.getArgumentsList(place); + if (elementToHighlight == null || elementToHighlight.getTextRange().getLength() == 0) elementToHighlight = place; + registerError(elementToHighlight, message); + } + private static String buildArgTypesList(PsiType[] argTypes) { StringBuilder builder = new StringBuilder(); builder.append("("); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/bugs/GroovyRangeTypeCheckInspection.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/bugs/GroovyRangeTypeCheckInspection.java index af384d9ce3cd..76d68bdd4c53 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/bugs/GroovyRangeTypeCheckInspection.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/bugs/GroovyRangeTypeCheckInspection.java @@ -130,6 +130,7 @@ public class GroovyRangeTypeCheckInspection extends BaseInspection { for (GroovyResolveResult method : methods) { final PsiElement el = method.getElement(); if (el instanceof PsiMethod && !((PsiMethod)el).hasModifierProperty(GrModifier.ABSTRACT)) result++; + else if (el instanceof PsiField) result++; } return result; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/copyright/UpdateGroovyCopyrightsProvider.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/copyright/UpdateGroovyCopyrightsProvider.java index af2d7df463a3..8ae953644721 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/copyright/UpdateGroovyCopyrightsProvider.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/copyright/UpdateGroovyCopyrightsProvider.java @@ -24,12 +24,19 @@ import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiComment; import com.intellij.psi.PsiElement; import com.maddyhome.idea.copyright.CopyrightProfile; +import com.maddyhome.idea.copyright.options.JavaOptions; import com.maddyhome.idea.copyright.psi.UpdateCopyright; import com.maddyhome.idea.copyright.psi.UpdateCopyrightsProvider; import com.maddyhome.idea.copyright.psi.UpdateJavaFileCopyright; 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.impl.synthetic.GroovyScriptClass; + +import java.util.List; public class UpdateGroovyCopyrightsProvider extends UpdateCopyrightsProvider { public UpdateCopyright createInstance(Project project, Module module, VirtualFile file, FileType base, CopyrightProfile options) { @@ -47,6 +54,21 @@ public class UpdateGroovyCopyrightsProvider extends UpdateCopyrightsProvider { protected PsiElement getPackageStatement() { return ((GroovyFile)getFile()).getPackageDefinition(); } + + @Override + protected void checkCommentsForTopClass(PsiClass topclass, int location, List comments) { + if (!(topclass instanceof GroovyScriptClass)) { + super.checkCommentsForTopClass(topclass, location, comments); + return; + } + final GroovyFile containingFile = (GroovyFile)topclass.getContainingFile(); + + PsiElement last = containingFile.getFirstChild(); + while (last != null && !(last instanceof GrStatement)) { + last = last.getNextSibling(); + } + checkComments(last, location == JavaOptions.LOCATION_BEFORE_CLASS, comments); + } }; } } \ No newline at end of file diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/filters/GroovyDebuggerClassFilterProvider.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/filters/GroovyDebuggerClassFilterProvider.java index 0d3f16fb22c9..ac50c0773ec6 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/filters/GroovyDebuggerClassFilterProvider.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/filters/GroovyDebuggerClassFilterProvider.java @@ -15,7 +15,6 @@ */ package org.jetbrains.plugins.groovy.debugger.filters; -import com.intellij.execution.filters.StackFrameFilter; import com.intellij.ui.classFilter.ClassFilter; import com.intellij.ui.classFilter.DebuggerClassFilterProvider; import com.intellij.util.containers.ContainerUtil; @@ -27,7 +26,7 @@ import java.util.List; /** * @author ilyas */ -public class GroovyDebuggerClassFilterProvider extends StackFrameFilter implements DebuggerClassFilterProvider { +public class GroovyDebuggerClassFilterProvider implements DebuggerClassFilterProvider { private static final ClassFilter[] FILTERS = {new ClassFilter("org.codehaus.groovy.*"), new ClassFilter("groovy.*")}; public List getFilters() { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionConfidence.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionConfidence.java index 9a8e82fb37a4..3baa252083b6 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionConfidence.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionConfidence.java @@ -14,10 +14,13 @@ package org.jetbrains.plugins.groovy.lang.completion; import com.intellij.codeInsight.completion.CompletionConfidence; import com.intellij.codeInsight.completion.CompletionParameters; +import com.intellij.codeInsight.completion.SkipAutopopupInStrings; import com.intellij.patterns.PsiJavaPatterns; import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; import com.intellij.util.ThreeState; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.gpp.GppTypeConverter; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; @@ -61,4 +64,10 @@ public class GroovyCompletionConfidence extends CompletionConfidence { } return ThreeState.UNSURE; } + + @NotNull + @Override + public ThreeState shouldSkipAutopopup(@Nullable PsiElement contextElement, @NotNull PsiFile psiFile, int offset) { + return new SkipAutopopupInStrings().shouldSkipAutopopup(contextElement, psiFile, offset); + } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java index 0061f91895ba..83811bf3114a 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java @@ -39,6 +39,7 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.Consumer; import com.intellij.util.PairConsumer; import com.intellij.util.ProcessingContext; +import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.GroovyBundle; import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement; @@ -48,6 +49,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.*; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral; import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameterList; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinitionBody; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAccessorMethod; @@ -63,7 +65,8 @@ import static com.intellij.patterns.PlatformPatterns.psiElement; import static com.intellij.patterns.PsiJavaPatterns.elementType; import static com.intellij.util.containers.CollectionFactory.hashMap; import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.*; -import static org.jetbrains.plugins.groovy.lang.lexer.TokenSets.*; +import static org.jetbrains.plugins.groovy.lang.lexer.TokenSets.SEPARATORS; +import static org.jetbrains.plugins.groovy.lang.lexer.TokenSets.WHITE_SPACES_OR_COMMENTS; /** * @author ilyas @@ -233,8 +236,7 @@ public class GroovyCompletionContributor extends CompletionContributor { } }); - - extend(CompletionType.CLASS_NAME, psiElement(), new CompletionProvider() { + extend(CompletionType.CLASS_NAME, psiElement(), new CompletionProvider() { @Override protected void addCompletions(@NotNull CompletionParameters parameters, ProcessingContext context, @@ -292,6 +294,25 @@ public class GroovyCompletionContributor extends CompletionContributor { } }); + extend(CompletionType.BASIC, psiElement().withParent(GrLiteral.class), new CompletionProvider() { + @Override + protected void addCompletions(@NotNull CompletionParameters parameters, + ProcessingContext context, + @NotNull final CompletionResultSet result) { + final Set usedWords = new THashSet(); + result.runRemainingContributors(parameters, new Consumer() { + public void consume(LookupElement element) { + result.addElement(element); + usedWords.add(element.getLookupString()); + } + }); + PsiReference reference = parameters.getPosition().getContainingFile().findReferenceAt(parameters.getOffset()); + if (reference == null || reference.isSoft()) { + WordCompletionContributor.addWordCompletionVariants(result, parameters, usedWords); + } + } + }); + } private static void addKeywords(CompletionParameters parameters, CompletionResultSet result) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/filters/control/BranchFilter.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/filters/control/BranchFilter.java index 66f3970264b0..074dab1eeee8 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/filters/control/BranchFilter.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/filters/control/BranchFilter.java @@ -19,11 +19,8 @@ package org.jetbrains.plugins.groovy.lang.completion.filters.control; import com.intellij.psi.PsiElement; import com.intellij.psi.filters.ElementFilter; import org.jetbrains.annotations.NonNls; -import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrForStatement; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrWhileStatement; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock; import org.jetbrains.plugins.groovy.lang.psi.api.statements.clauses.GrCaseSection; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; @@ -34,31 +31,7 @@ public class BranchFilter implements ElementFilter { public boolean isAcceptable(Object element, PsiElement context) { if (context.getParent() != null) { PsiElement parent = context.getParent(); - - if (parent instanceof GrReferenceExpression && - treeWalkUp(parent)) { - PsiElement superParent = parent.getParent(); - if ((superParent instanceof GrOpenBlock || - superParent instanceof GrCaseSection || - superParent instanceof GrClosableBlock)) { - return true; - } - - if (superParent instanceof GrWhileStatement) { - PsiElement elem = parent.getPrevSibling(); - while (elem != null && - !GroovyElementTypes.mRPAREN.equals(elem.getNode().getElementType())) { - elem = elem.getPrevSibling(); - } - if (elem != null) { - return true; - } else { - return false; - } - } - } - - return false; + return parent instanceof GrReferenceExpression && treeWalkUp(parent); } return false; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/lexer/TokenSets.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/lexer/TokenSets.java index 3ef85844537b..b69e99d0bf0b 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/lexer/TokenSets.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/lexer/TokenSets.java @@ -17,15 +17,20 @@ package org.jetbrains.plugins.groovy.lang.lexer; import com.intellij.psi.TokenType; +import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.TokenSet; -import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes; +import com.intellij.util.containers.hash.HashMap; + +import static org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes.*; + +import java.util.Map; /** * Utility classdef, tha contains various useful TokenSets * * @author ilyas */ -public abstract class TokenSets implements GroovyTokenTypes, GroovyElementTypes { +public abstract class TokenSets { public static TokenSet COMMENTS_TOKEN_SET = TokenSet.create( mSL_COMMENT, @@ -150,11 +155,45 @@ public abstract class TokenSets implements GroovyTokenTypes, GroovyElementTypes public static final TokenSet POSTFIX_UNARY_OP_SET = TokenSet.create(mDEC, mINC); - public static final TokenSet BINARY_OP_SET = TokenSet.create(mBAND, mBOR, mBXOR, mDIV, mEQUAL, mGE, mGT, mLAND, mLOR, mLT, mLE, mMINUS, - mMOD, mPLUS, mSTAR, mSTAR_STAR, mNOT_EQUAL, mCOMPARE_TO, - COMPOSITE_SHIFT_SIGN, kIN, kINSTANCEOF, kAS); + public static final TokenSet BINARY_OP_SET = TokenSet.create(mBAND, mBOR, mBXOR, mDIV, mEQUAL, mGE, mGT, mLOR, mLT, mLE, mMINUS, kAS, kIN, + mMOD, mPLUS, mSTAR, mSTAR_STAR, mNOT_EQUAL, mCOMPARE_TO, mLAND, kINSTANCEOF, + COMPOSITE_LSHIFT_SIGN, COMPOSITE_RSHIFT_SIGN, COMPOSITE_TRIPLE_SHIFT_SIGN); public static final TokenSet DOTS = TokenSet.create(mSPREAD_DOT, mOPTIONAL_DOT, mMEMBER_POINTER, mDOT); public static final TokenSet WHITE_SPACES_OR_COMMENTS = TokenSet.orSet(WHITE_SPACES_SET, COMMENT_SET); + + public static final Map ASSIGNMENTS_TO_OPERATORS = new HashMap(); + static { + ASSIGNMENTS_TO_OPERATORS.put(mMINUS_ASSIGN, mMINUS); + ASSIGNMENTS_TO_OPERATORS.put(mPLUS_ASSIGN, mPLUS); + ASSIGNMENTS_TO_OPERATORS.put(mDIV_ASSIGN, mDIV); + ASSIGNMENTS_TO_OPERATORS.put(mSTAR_ASSIGN, mSTAR); + ASSIGNMENTS_TO_OPERATORS.put(mMOD_ASSIGN, mMOD); + ASSIGNMENTS_TO_OPERATORS.put(mSL_ASSIGN, COMPOSITE_LSHIFT_SIGN); + ASSIGNMENTS_TO_OPERATORS.put(mSR_ASSIGN, COMPOSITE_RSHIFT_SIGN); + ASSIGNMENTS_TO_OPERATORS.put(mBSR_ASSIGN, COMPOSITE_TRIPLE_SHIFT_SIGN); + ASSIGNMENTS_TO_OPERATORS.put(mBAND_ASSIGN, mBAND); + ASSIGNMENTS_TO_OPERATORS.put(mBOR_ASSIGN, mBOR); + ASSIGNMENTS_TO_OPERATORS.put(mBXOR_ASSIGN, mBXOR); + ASSIGNMENTS_TO_OPERATORS.put(mSTAR_STAR_ASSIGN, mSTAR_STAR); + } + + public static final TokenSet ASSIGNMENTS = TokenSet.create( + mASSIGN, + mPLUS_ASSIGN, + mMINUS_ASSIGN, + mSTAR_ASSIGN, + mDIV_ASSIGN, + mMOD_ASSIGN, + mSL_ASSIGN, + mSR_ASSIGN, + mBSR_ASSIGN, + mBAND_ASSIGN, + mBOR_ASSIGN, + mBXOR_ASSIGN, + mSTAR_STAR_ASSIGN + ); + + public static final TokenSet SHIFT_SIGNS = TokenSet.create(COMPOSITE_LSHIFT_SIGN, COMPOSITE_RSHIFT_SIGN, COMPOSITE_TRIPLE_SHIFT_SIGN); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/GroovyElementTypes.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/GroovyElementTypes.java index 4e9463950056..01a5c6797389 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/GroovyElementTypes.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/GroovyElementTypes.java @@ -196,7 +196,10 @@ public interface GroovyElementTypes extends GroovyTokenTypes, GroovyDocElementTy GroovyElementType RELATIONAL_EXPRESSION = new GroovyElementType("Relational expression"); GroovyElementType SHIFT_EXPRESSION = new GroovyElementType("Shift expression"); GroovyElementType RANGE_EXPRESSION = new GroovyElementType("Range expression"); - GroovyElementType COMPOSITE_SHIFT_SIGN = new GroovyElementType("Composite shift sign"); + GroovyElementType COMPOSITE_LSHIFT_SIGN = new GroovyElementType("Composite shift sign <<"); + GroovyElementType COMPOSITE_RSHIFT_SIGN = new GroovyElementType("Composite shift sign >>"); + GroovyElementType COMPOSITE_TRIPLE_SHIFT_SIGN = new GroovyElementType("Composite shift sign >>>"); + GroovyElementType MORE_OR_EQUALS_SIGN = new GroovyElementType(">="); GroovyElementType ADDITIVE_EXPRESSION = new GroovyElementType("Additive expression"); GroovyElementType MULTIPLICATIVE_EXPRESSION = new GroovyElementType("Multiplicative expression"); GroovyElementType POWER_EXPRESSION = new GroovyElementType("Power expression"); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/GroovyPsiCreator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/GroovyPsiCreator.java index 919782117ea8..6e487818ca46 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/GroovyPsiCreator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/GroovyPsiCreator.java @@ -23,6 +23,7 @@ import com.intellij.psi.tree.IElementType; import org.jetbrains.plugins.groovy.lang.groovydoc.lexer.IGroovyDocElementType; import org.jetbrains.plugins.groovy.lang.groovydoc.psi.GroovyDocPsiCreator; import org.jetbrains.plugins.groovy.lang.lexer.GroovyElementType; +import org.jetbrains.plugins.groovy.lang.lexer.TokenSets; import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiElementImpl; import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.GrLabelImpl; import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.GrListOrMapImpl; @@ -212,7 +213,7 @@ public class GroovyPsiCreator implements GroovyElementTypes { if (elem.equals(RELATIONAL_EXPRESSION)) return new GrRelationalExpressionImpl(node); if (elem.equals(SHIFT_EXPRESSION)) return new GrShiftExpressionImpl(node); if (elem.equals(RANGE_EXPRESSION)) return new GrRangeExpressionImpl(node); - if (elem.equals(COMPOSITE_SHIFT_SIGN)) return new GrOperationSignImpl(node); + if (TokenSets.SHIFT_SIGNS.contains(elem)) return new GrOperationSignImpl(node); if (elem.equals(ADDITIVE_EXPRESSION)) return new GrAdditiveExpressionImpl(node); if (elem.equals(MULTIPLICATIVE_EXPRESSION)) return new GrMultiplicativeExpressionImpl(node); if (elem.equals(POWER_EXPRESSION)) return new GrPowerExpressionImpl(node); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/AssignmentExpression.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/AssignmentExpression.java index ee983d7bcba7..479ad8ba3b28 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/AssignmentExpression.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/AssignmentExpression.java @@ -18,8 +18,8 @@ package org.jetbrains.plugins.groovy.lang.parser.parsing.statements.expressions; import com.intellij.lang.PsiBuilder; import com.intellij.lang.PsiBuilder.Marker; -import com.intellij.psi.tree.TokenSet; import org.jetbrains.plugins.groovy.GroovyBundle; +import org.jetbrains.plugins.groovy.lang.lexer.TokenSets; import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes; import org.jetbrains.plugins.groovy.lang.parser.GroovyParser; import org.jetbrains.plugins.groovy.lang.parser.parsing.statements.TupleParse; @@ -31,22 +31,6 @@ import org.jetbrains.plugins.groovy.lang.parser.parsing.util.ParserUtils; */ public class AssignmentExpression implements GroovyElementTypes { - private static final TokenSet ASSIGNMENTS = TokenSet.create( - mASSIGN, - mPLUS_ASSIGN, - mMINUS_ASSIGN, - mSTAR_ASSIGN, - mDIV_ASSIGN, - mMOD_ASSIGN, - mSL_ASSIGN, - mBAND_ASSIGN, - mBOR_ASSIGN, - mBXOR_ASSIGN, - mSTAR_STAR_ASSIGN, - mSR_ASSIGN, - mBSR_ASSIGN - ); - public static boolean parse(PsiBuilder builder, GroovyParser parser) { return parse(builder, parser, false); } @@ -55,7 +39,7 @@ public class AssignmentExpression implements GroovyElementTypes { Marker marker = builder.mark(); final boolean isTuple = ParserUtils.lookAhead(builder, mLPAREN, mIDENT, mCOMMA); if (parseSide(builder, parser, isTuple,comExprAllowed)) { - if (ParserUtils.getToken(builder, ASSIGNMENTS)) { + if (ParserUtils.getToken(builder, TokenSets.ASSIGNMENTS)) { ParserUtils.getToken(builder, mNLS); if (!parse(builder, parser, comExprAllowed)) { builder.error(GroovyBundle.message("expression.expected")); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/arithmetic/ShiftExpression.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/arithmetic/ShiftExpression.java index 5085aef545d9..a924467343e9 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/arithmetic/ShiftExpression.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/arithmetic/ShiftExpression.java @@ -80,18 +80,28 @@ public class ShiftExpression implements GroovyElementTypes { builder.getTokenText(); //todo[peter] remove look-ahead assertion builder.advanceLexer(); } - marker.done(COMPOSITE_SHIFT_SIGN); + marker.done(COMPOSITE_TRIPLE_SHIFT_SIGN); return true; - } else if (ParserUtils.lookAhead(builder, mLT, mLT) || - ParserUtils.lookAhead(builder, mGT, mGT)) { + } + else if (ParserUtils.lookAhead(builder, mLT, mLT)) { PsiBuilder.Marker marker = builder.mark(); for (int i = 0; i < 2; i++) { builder.getTokenText(); //todo[peter] remove look-ahead assertion builder.advanceLexer(); } - marker.done(COMPOSITE_SHIFT_SIGN); + marker.done(COMPOSITE_LSHIFT_SIGN); return true; - } else { + } + else if (ParserUtils.lookAhead(builder, mGT, mGT)) { + PsiBuilder.Marker marker = builder.mark(); + for (int i = 0; i < 2; i++) { + builder.getTokenText(); //todo[peter] remove look-ahead assertion + builder.advanceLexer(); + } + marker.done(COMPOSITE_RSHIFT_SIGN); + return true; + } + else { return false; } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/relational/RelationalExpression.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/relational/RelationalExpression.java index e00b0bfd7895..3b349a84a28f 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/relational/RelationalExpression.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/relational/RelationalExpression.java @@ -82,7 +82,7 @@ public class RelationalExpression implements GroovyElementTypes { for (int i = 0; i < 2; i++) { builder.advanceLexer(); } - marker.done(COMPOSITE_SHIFT_SIGN); + marker.done(MORE_OR_EQUALS_SIGN); return true; } else { return false; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GroovyPsiElementFactory.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GroovyPsiElementFactory.java index ae37d188e462..0f0b209d4511 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GroovyPsiElementFactory.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GroovyPsiElementFactory.java @@ -20,6 +20,7 @@ import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.GrDocComment; @@ -55,6 +56,8 @@ import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement; */ public abstract class GroovyPsiElementFactory { + @NonNls public static final String DUMMY_FILE_NAME = "DUMMY__"; + public static GroovyPsiElementFactory getInstance(Project project) { return ServiceManager.getService(project, GroovyPsiElementFactory.class); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/GrForStatement.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/GrForStatement.java index a3939d8451ee..a6f1982010ce 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/GrForStatement.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/GrForStatement.java @@ -16,9 +16,9 @@ package org.jetbrains.plugins.groovy.lang.psi.api.statements; +import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.api.formatter.GrControlStatement; import org.jetbrains.plugins.groovy.lang.psi.api.statements.clauses.GrForClause; -import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; import com.intellij.psi.PsiElement; /** @@ -26,12 +26,14 @@ import com.intellij.psi.PsiElement; */ public interface GrForStatement extends GrControlStatement, GrLoopStatement { - public GrForClause getClause(); + @Nullable + GrForClause getClause(); - public GrStatement getBody(); + @Nullable + GrStatement getBody(); - public PsiElement getRParenth(); + PsiElement getRParenth(); - public PsiElement getLParenth(); + PsiElement getLParenth(); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/blocks/GrCodeBlock.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/blocks/GrCodeBlock.java index e873fd7d4675..2c6ab42266ca 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/blocks/GrCodeBlock.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/blocks/GrCodeBlock.java @@ -29,9 +29,6 @@ import org.jetbrains.plugins.groovy.lang.psi.api.util.GrDeclarationHolder; * @author ilyas */ public interface GrCodeBlock extends GrControlFlowOwner, GrVariableDeclarationOwner, GrStatementOwner, GrDeclarationHolder { - @NotNull - GrStatement[] getStatements(); - @Nullable PsiElement getLBrace(); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/clauses/GrCaseSection.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/clauses/GrCaseSection.java index 3624c8325098..2c7e573010a6 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/clauses/GrCaseSection.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/clauses/GrCaseSection.java @@ -17,7 +17,6 @@ package org.jetbrains.plugins.groovy.lang.psi.api.statements.clauses; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement; import org.jetbrains.plugins.groovy.lang.psi.api.util.GrStatementOwner; import org.jetbrains.plugins.groovy.lang.psi.api.util.GrVariableDeclarationOwner; import org.jetbrains.plugins.groovy.lang.psi.api.util.GrDeclarationHolder; @@ -26,9 +25,5 @@ import org.jetbrains.plugins.groovy.lang.psi.api.util.GrDeclarationHolder; * @author ilyas */ public interface GrCaseSection extends GroovyPsiElement, GrVariableDeclarationOwner, GrStatementOwner, GrDeclarationHolder { - GrCaseLabel getCaseLabel(); - - GrStatement[] getStatements(); - } \ No newline at end of file diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/GrAssignmentExpression.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/GrAssignmentExpression.java index 2f78a6d2e02b..78fba067f194 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/GrAssignmentExpression.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/GrAssignmentExpression.java @@ -16,22 +16,30 @@ package org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiPolyVariantReference; import com.intellij.psi.tree.IElementType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; /** * @author ilyas */ -public interface GrAssignmentExpression extends GrExpression { +public interface GrAssignmentExpression extends GrExpression, PsiPolyVariantReference { boolean isTupleAssignment(); @NotNull - public GrExpression getLValue(); + GrExpression getLValue(); @Nullable - public GrExpression getRValue(); + GrExpression getRValue(); IElementType getOperationToken(); + + @NotNull + GroovyResolveResult[] multiResolve(boolean incompleteCode); + + PsiElement getOpToken(); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/GrSafeCastExpression.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/GrSafeCastExpression.java index b4a5cb565659..b707ff01b6c7 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/GrSafeCastExpression.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/GrSafeCastExpression.java @@ -18,6 +18,7 @@ package org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions; import com.intellij.psi.PsiPolyVariantReference; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement; @@ -25,7 +26,10 @@ import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement; * @author ven */ public interface GrSafeCastExpression extends GrExpression, PsiPolyVariantReference { + @Nullable GrTypeElement getCastTypeElement(); + + @NotNull GrExpression getOperand(); @NotNull diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/util/GrStatementOwner.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/util/GrStatementOwner.java index c01582ce84f0..ebe539bda523 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/util/GrStatementOwner.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/util/GrStatementOwner.java @@ -31,4 +31,6 @@ public interface GrStatementOwner extends GroovyPsiElement { void removeElements(PsiElement[] elements) throws IncorrectOperationException; + @NotNull + GrStatement[] getStatements(); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/types/TypeDfaInstance.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/types/TypeDfaInstance.java index c32de5b6689c..b7e765dd5672 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/types/TypeDfaInstance.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/types/TypeDfaInstance.java @@ -72,16 +72,12 @@ public class TypeDfaInstance implements DfaInstance> { if (element instanceof GrReferenceExpression && ((GrReferenceExpression) element).getQualifierExpression() == null) { final PsiElement parent = element.getParent(); if (parent instanceof GrAssignmentExpression) { - final GrExpression initializer = ((GrAssignmentExpression)parent).getRValue(); - if (initializer != null) { - return new Computable() { - @Nullable - public PsiType compute() { - return initializer.getType(); - } - }; - } - return null; + return new Computable() { + @Nullable + public PsiType compute() { + return ((GrAssignmentExpression)parent).getType(); + } + }; } if (parent instanceof GrTupleExpression) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesProvider.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesProvider.java index d1b609dfafa5..76bd3b74ef0b 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesProvider.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesProvider.java @@ -19,6 +19,7 @@ import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Pair; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -267,9 +268,11 @@ public class GroovyExpectedTypesProvider { TypeConstraint constraint = new TypeConstraint(PsiType.INT) { @Override public boolean satisfied(PsiType type, PsiManager manager, GlobalSearchScope scope) { - return TypesUtil - .getOverloadedOperatorCandidates(TypesUtil.boxPrimitiveType(type, manager, scope), expression.getOperationTokenType(), - expression, PsiType.EMPTY_ARRAY).length > 0; + final PsiType boxed = TypesUtil.boxPrimitiveType(type, manager, scope); + final IElementType opToken = expression.getOperationTokenType(); + final GroovyResolveResult[] candidates = + TypesUtil.getOverloadedOperatorCandidates(boxed, opToken, expression, PsiType.EMPTY_ARRAY); + return candidates.length > 0; } @NotNull diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrTupleType.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrTupleType.java index e2b020587fd8..35ff1dd03080 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrTupleType.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrTupleType.java @@ -43,11 +43,11 @@ public class GrTupleType extends GrLiteralClassType { @Override protected String getJavaClassName() { - return CommonClassNames.JAVA_UTIL_LIST; + return CommonClassNames.JAVA_UTIL_ARRAY_LIST; } public String getClassName() { - return "List"; + return "ArrayList"; } @NotNull diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileBaseImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileBaseImpl.java index 0a305969d230..39caeac704cb 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileBaseImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileBaseImpl.java @@ -147,6 +147,12 @@ public abstract class GroovyFileBaseImpl extends PsiFileBase implements GroovyFi } } + @NotNull + @Override + public GrStatement[] getStatements() { + return findChildrenByClass(GrStatement.class); + } + public GrStatement addStatementBefore(@NotNull GrStatement statement, @Nullable GrStatement anchor) throws IncorrectOperationException { final PsiElement result = addBefore(statement, anchor); if (anchor != null) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiElementFactoryImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiElementFactoryImpl.java index 412c5cad4465..84e48f951fc8 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiElementFactoryImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiElementFactoryImpl.java @@ -259,7 +259,7 @@ public class GroovyPsiElementFactoryImpl extends GroovyPsiElementFactory { } private GroovyFileImpl createDummyFile(String text, boolean physical) { - final String fileName = "DUMMY__." + GroovyFileType.GROOVY_FILE_TYPE.getDefaultExtension(); + final String fileName = DUMMY_FILE_NAME + '.' + GroovyFileType.GROOVY_FILE_TYPE.getDefaultExtension(); final long stamp = System.currentTimeMillis(); final PsiFileFactory factory = PsiFileFactory.getInstance(myProject); return (GroovyFileImpl) factory.createFileFromText(fileName, GroovyFileType.GROOVY_FILE_TYPE, text, stamp, physical); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/PsiImplUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/PsiImplUtil.java index 01aba2e4633c..7cc62356f405 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/PsiImplUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/PsiImplUtil.java @@ -62,8 +62,7 @@ import java.util.List; import static com.intellij.psi.impl.source.tree.Factory.createSingleLeafElement; import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.*; -import static org.jetbrains.plugins.groovy.lang.lexer.TokenSets.RELATIONS; -import static org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes.COMPOSITE_SHIFT_SIGN; +import static org.jetbrains.plugins.groovy.lang.lexer.TokenSets.*; /** * @@ -176,7 +175,7 @@ public class PsiImplUtil { } return RELATIONS.contains(opToken) || opToken == mCOMPARE_TO || opToken == mREGEX_FIND || opToken == mREGEX_MATCH - || opToken == COMPOSITE_SHIFT_SIGN + || SHIFT_SIGNS.contains(opToken) || opToken==mSTAR; } @@ -263,7 +262,7 @@ public class PsiImplUtil { if (opToken == mSTAR_STAR) priority = 7; else if (opToken == mSTAR || opToken == mDIV) priority = 8; else if (opToken == mPLUS || opToken == mMINUS) priority = 9; - else if (opToken == COMPOSITE_SHIFT_SIGN) priority = 10; + else if (SHIFT_SIGNS.contains(opToken)) priority = 10; else if (RELATIONS.contains(opToken)) priority = 12; else if (opToken == mEQUAL || opToken == mNOT_EQUAL || opToken == mCOMPARE_TO) priority = 13; else if (opToken == mREGEX_FIND || opToken == mREGEX_MATCH) priority = 14; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/GrForStatementImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/GrForStatementImpl.java index db10038af539..bcf67bf428a0 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/GrForStatementImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/GrForStatementImpl.java @@ -18,12 +18,12 @@ package org.jetbrains.plugins.groovy.lang.psi.impl.statements; import com.intellij.lang.ASTNode; import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiModifierList; import com.intellij.psi.ResolveState; import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory; @@ -52,10 +52,12 @@ public class GrForStatementImpl extends GroovyPsiElementImpl implements GrForSta return "For statement"; } + @Nullable public GrForClause getClause() { return findChildByClass(GrForClause.class); } + @Nullable public GrStatement getBody() { return findChildByClass(GrStatement.class); } @@ -67,15 +69,11 @@ public class GrForStatementImpl extends GroovyPsiElementImpl implements GrForSta GrForClause forClause = getClause(); final GrVariable varScope = PsiTreeUtil.getParentOfType(place, GrVariable.class); if (forClause == null) return true; + if (lastParent == null || lastParent instanceof GrForInClause) return true; GrVariable var = forClause.getDeclaredVariable(); - if (var == null) return true; - - final PsiModifierList modifierList = var.getModifierList(); - boolean isAvailableOutsideOfFor = modifierList == null || modifierList.getTextLength() == 0; - if (lastParent != null && !(lastParent instanceof GrForInClause) || lastParent == null && isAvailableOutsideOfFor) { - if (!var.equals(varScope) && !ResolveUtil.processElement(processor, var, state)) return false; - } + if (var == null || var.equals(varScope)) return true; + if (!ResolveUtil.processElement(processor, var, state)) return false; return true; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/clauses/GrCaseSectionImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/clauses/GrCaseSectionImpl.java index 2ccb93a65a93..7c5e86806d17 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/clauses/GrCaseSectionImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/clauses/GrCaseSectionImpl.java @@ -68,6 +68,7 @@ public class GrCaseSectionImpl extends GroovyPsiElementImpl implements GrCaseSec return findChildByClass(GrCaseLabel.class); } + @NotNull public GrStatement[] getStatements() { return findChildrenByClass(GrStatement.class); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/CompleteReferenceExpression.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/CompleteReferenceExpression.java index 7452788e63e5..f6ff4cc4b753 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/CompleteReferenceExpression.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/CompleteReferenceExpression.java @@ -46,7 +46,6 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager; import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyResolveResultImpl; import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; import org.jetbrains.plugins.groovy.lang.psi.util.GrClassImplUtil; -import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import org.jetbrains.plugins.groovy.lang.resolve.ClosureMissingMethodContributor; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; @@ -438,7 +437,7 @@ public class CompleteReferenceExpression { @Override public GroovyResolveResult[] getCandidates() { if (!hasCandidates()) return GroovyResolveResult.EMPTY_ARRAY; - final GroovyResolveResult[] results = ResolveUtil.filterSameSignatureCandidates(getCandidatesInternal(), -1); + final GroovyResolveResult[] results = ResolveUtil.filterSameSignatureCandidates(getCandidatesInternal()); List list = new ArrayList(results.length); myPropertyNames.removeAll(myPreferredFieldNames); for (GroovyResolveResult result : results) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrAssignmentExpressionImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrAssignmentExpressionImpl.java index ac62d6074384..37630b24eae9 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrAssignmentExpressionImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrAssignmentExpressionImpl.java @@ -17,21 +17,29 @@ package org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions; import com.intellij.lang.ASTNode; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiType; -import com.intellij.psi.PsiVariable; -import com.intellij.psi.ResolveState; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.*; +import com.intellij.psi.impl.source.resolve.ResolveCache; import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.tree.IElementType; +import com.intellij.util.ArrayUtil; +import com.intellij.util.Function; +import com.intellij.util.IncorrectOperationException; +import com.intellij.util.NullableFunction; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; import org.jetbrains.plugins.groovy.lang.lexer.TokenSets; import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor; +import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrTupleDeclaration; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrAssignmentExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAccessorMethod; +import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager; +import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; +import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; import org.jetbrains.plugins.groovy.lang.resolve.processors.ResolverProcessor; /** @@ -39,6 +47,28 @@ import org.jetbrains.plugins.groovy.lang.resolve.processors.ResolverProcessor; */ public class GrAssignmentExpressionImpl extends GrExpressionImpl implements GrAssignmentExpression { + private static final Function TYPE_CALCULATOR = + new NullableFunction() { + @Override + public PsiType fun(GrAssignmentExpressionImpl assignment) { + final GroovyResolveResult[] results = assignment.multiResolve(false); + + if (results.length == 0) { + final GrExpression rValue = assignment.getRValue(); + return rValue == null ? null : rValue.getType(); + } + + + PsiType returnType = null; + final PsiManager manager = assignment.getManager(); + for (GroovyResolveResult result : results) { + final PsiType substituted = ResolveUtil.extractReturnTypeFromCandidate(result); + returnType = TypesUtil.getLeastUpperBoundNullable(returnType, substituted, manager); + } + return returnType; + } + }; + public GrAssignmentExpressionImpl(@NotNull ASTNode node) { super(node); } @@ -66,11 +96,15 @@ public class GrAssignmentExpressionImpl extends GrExpressionImpl implements GrAs } public IElementType getOperationToken() { - return findNotNullChildByType(TokenSets.ASSIGN_OP_SET).getNode().getElementType(); + return getOpToken().getNode().getElementType(); + } + + public PsiElement getOpToken() { + return findNotNullChildByType(TokenSets.ASSIGN_OP_SET); } public PsiType getType() { - return getLValue().getType(); + return GroovyPsiManager.getInstance(getProject()).getType(this, TYPE_CALCULATOR); } public boolean processDeclarations(@NotNull PsiScopeProcessor processor, @NotNull ResolveState state, PsiElement lastParent, @NotNull PsiElement place) { @@ -102,4 +136,87 @@ public class GrAssignmentExpressionImpl extends GrExpressionImpl implements GrAs public void accept(GroovyElementVisitor visitor) { visitor.visitAssignmentExpression(this); } + + @NotNull + @Override + public GroovyResolveResult[] multiResolve(boolean incompleteCode) { + return (GroovyResolveResult[])getManager().getResolveCache().resolveWithCaching(this, RESOLVER, false, incompleteCode); + } + + @Override + public PsiElement getElement() { + return this; + } + + @Override + public TextRange getRangeInElement() { + final PsiElement token = getOpToken(); + assert token != null; + final int offset = token.getStartOffsetInParent(); + return new TextRange(offset, offset + token.getTextLength()); + } + + @Override + public PsiElement resolve() { + return PsiImplUtil.extractUniqueElement(multiResolve(false)); + } + + @NotNull + @Override + public String getCanonicalText() { + return getText(); + } + + @Override + public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException { + throw new IncorrectOperationException("assignment expression cannot be renamed"); + } + + @Override + public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException { + throw new IncorrectOperationException("assignment expression cannot be bound to anything"); + } + + @Override + public boolean isReferenceTo(PsiElement element) { + return getManager().areElementsEquivalent(resolve(), element); + } + + @NotNull + @Override + public Object[] getVariants() { + return ArrayUtil.EMPTY_OBJECT_ARRAY; + } + + @Override + public boolean isSoft() { + return false; + } + + @Override + public PsiReference getReference() { + final IElementType operationToken = getOperationToken(); + if (operationToken == GroovyTokenTypes.mASSIGN) return null; + + return this; + } + + private static final ResolveCache.PolyVariantResolver RESOLVER = + new ResolveCache.PolyVariantResolver() { + @Override + public GroovyResolveResult[] resolve(GrAssignmentExpressionImpl assignmentExpression, boolean incompleteCode) { + final IElementType opType = assignmentExpression.getOperationToken(); + if (opType == null || opType == GroovyTokenTypes.mASSIGN) return GroovyResolveResult.EMPTY_ARRAY; + + final PsiType lType = assignmentExpression.getLValue().getType(); + if (lType == null) return GroovyResolveResult.EMPTY_ARRAY; + + final GrExpression rightOperand = assignmentExpression.getRValue(); + PsiType rType = rightOperand == null ? null : rightOperand.getType(); + + final IElementType operatorToken = TokenSets.ASSIGNMENTS_TO_OPERATORS.get(opType); + return TypesUtil.getOverloadedOperatorCandidates(lType, operatorToken, assignmentExpression, new PsiType[]{rType}); + } + }; + } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrBinaryExpressionImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrBinaryExpressionImpl.java index c7b04d8eed85..082eef319664 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrBinaryExpressionImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrBinaryExpressionImpl.java @@ -19,7 +19,6 @@ package org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions; import com.intellij.lang.ASTNode; import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiReference; import com.intellij.psi.PsiType; import com.intellij.psi.impl.source.resolve.ResolveCache; @@ -36,7 +35,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrBinary import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager; import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; -import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; +import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; /** * @author ilyas @@ -70,13 +69,8 @@ public abstract class GrBinaryExpressionImpl extends GrExpressionImpl implements } final GroovyResolveResult resolveResult = PsiImplUtil.extractUniqueResult(binary.multiResolve(false)); - final PsiElement resolved = resolveResult.getElement(); - if (resolved instanceof PsiMethod) { - final PsiType returnType = PsiUtil.getSmartReturnType((PsiMethod)resolved); - final PsiType substituted = resolveResult.getSubstitutor().substitute(returnType); - return TypesUtil.boxPrimitiveType(substituted, binary.getManager(), binary.getResolveScope()); - } - return null; + final PsiType substituted = ResolveUtil.extractReturnTypeFromCandidate(resolveResult); + return TypesUtil.boxPrimitiveType(substituted, binary.getManager(), binary.getResolveScope()); } }; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrThisReferenceExpressionImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrThisReferenceExpressionImpl.java index 4f250081fffe..1ffe4899cb58 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrThisReferenceExpressionImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrThisReferenceExpressionImpl.java @@ -2,6 +2,7 @@ package org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions; import com.intellij.lang.ASTNode; +import com.intellij.openapi.util.io.FileUtil; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.IncorrectOperationException; @@ -9,6 +10,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor; import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; +import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrThisReferenceExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; @@ -33,7 +35,7 @@ public class GrThisReferenceExpressionImpl extends GrThisSuperReferenceExpressio public PsiType getType() { final GrReferenceExpression qualifier = getQualifier(); if (qualifier == null) { - GroovyPsiElement context = PsiTreeUtil.getContextOfType(this, GrTypeDefinition.class, GroovyFile.class); + GroovyPsiElement context = getFileContext(); if (context instanceof GrTypeDefinition) { return createType((PsiClass)context); } @@ -59,6 +61,15 @@ public class GrThisReferenceExpressionImpl extends GrThisSuperReferenceExpressio return null; } + private GroovyPsiElement getFileContext() { + GroovyPsiElement context = PsiTreeUtil.getContextOfType(this, GrTypeDefinition.class, GroovyFile.class); + if (context instanceof GroovyFile && GroovyPsiElementFactory.DUMMY_FILE_NAME.equals(FileUtil.getNameWithoutExtension( + ((GroovyFile)context).getName()))) { + context = PsiTreeUtil.getContextOfType(context, true, GrTypeDefinition.class, GroovyFile.class); + } + return context; + } + private PsiType createType(PsiClass context) { PsiElementFactory elementFactory = JavaPsiFacade.getInstance(getProject()).getElementFactory(); if (PsiUtil.isInStaticContext(this)) { @@ -83,11 +94,12 @@ public class GrThisReferenceExpressionImpl extends GrThisSuperReferenceExpressio return qualifier.resolve(); } - final GrTypeDefinition containingClass = PsiTreeUtil.getContextOfType(this, GrTypeDefinition.class, true, GroovyFile.class); - if (containingClass != null) return containingClass; - final PsiFile containingFile = getContainingFile(); - if (containingFile instanceof GroovyFile) { - return ((GroovyFile)containingFile).getScriptClass(); + final GroovyPsiElement context = getFileContext(); + if (context instanceof GrTypeDefinition) { + return context; + } + else if (context instanceof GroovyFile) { + return ((GroovyFile)context).getScriptClass(); } return null; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/arithmetic/GrUnaryExpressionImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/arithmetic/GrUnaryExpressionImpl.java index bf082bc4899d..35edaf526047 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/arithmetic/GrUnaryExpressionImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/arithmetic/GrUnaryExpressionImpl.java @@ -37,7 +37,7 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.GrExpressionImpl; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames; -import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; +import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; /** * @author ilyas @@ -54,16 +54,13 @@ public class GrUnaryExpressionImpl extends GrExpressionImpl implements GrUnaryEx PsiType opType = operand.getType(); if (opType == null) return null; - IElementType opToken = unary.getOperationTokenType(); - final GroovyResolveResult resolveResult = PsiImplUtil.extractUniqueResult(unary.multiResolve(false)); - final PsiElement resolved = resolveResult.getElement(); - if (resolved instanceof PsiMethod) { - final PsiType smartReturnType = PsiUtil.getSmartReturnType((PsiMethod)resolved); - final PsiType substituted = resolveResult.getSubstitutor().substitute(smartReturnType); + final PsiType substituted = ResolveUtil.extractReturnTypeFromCandidate(resolveResult); + if (substituted != null) { return TypesUtil.boxPrimitiveType(substituted, unary.getManager(), unary.getResolveScope()); } + IElementType opToken = unary.getOperationTokenType(); if (opToken == GroovyTokenTypes.mBNOT && opType.equalsToText(CommonClassNames.JAVA_LANG_STRING)) { return unary.getTypeByFQName(GroovyCommonClassNames.JAVA_UTIL_REGEX_PATTERN); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/path/DefaultCallExpressionTypeCalculator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/path/DefaultCallExpressionTypeCalculator.java index 4af9de2c3893..0ce48ab7a464 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/path/DefaultCallExpressionTypeCalculator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/path/DefaultCallExpressionTypeCalculator.java @@ -21,6 +21,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; @@ -105,11 +106,8 @@ public class DefaultCallExpressionTypeCalculator extends GrCallExpressionTypeCal returnType = null; final PsiManager manager = callExpression.getManager(); for (GroovyResolveResult call : calls) { - final PsiElement element = call.getElement(); - if (element instanceof PsiMethod) { - final PsiType substituted = call.getSubstitutor().substitute(PsiUtil.getSmartReturnType((PsiMethod)element)); - returnType = TypesUtil.getLeastUpperBoundNullable(returnType, substituted, manager); - } + final PsiType substituted = ResolveUtil.extractReturnTypeFromCandidate(call); + returnType = TypesUtil.getLeastUpperBoundNullable(returnType, substituted, manager); } } return returnType; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/path/GrIndexPropertyImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/path/GrIndexPropertyImpl.java index 882bb8caa962..b91092fe6a8a 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/path/GrIndexPropertyImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/path/GrIndexPropertyImpl.java @@ -20,6 +20,8 @@ import com.intellij.lang.ASTNode; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.InheritanceUtil; +import com.intellij.util.Function; +import com.intellij.util.NullableFunction; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor; @@ -27,19 +29,60 @@ import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrIndexProperty; +import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager; import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.GrExpressionImpl; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; +import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; import static com.intellij.psi.util.PsiUtil.substituteTypeParameter; -import static org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil.getSmartReturnType; /** * @author ilyas */ public class GrIndexPropertyImpl extends GrExpressionImpl implements GrIndexProperty { + private static final Function TYPE_CALCULATOR = new NullableFunction() { + @Override + public PsiType fun(GrIndexPropertyImpl index) { + GrExpression selected = index.getSelectedExpression(); + PsiType thisType = selected.getType(); + + if (thisType == null) return null; + + GrArgumentList argList = index.getArgumentList(); + if (argList == null) return null; + + PsiType[] argTypes = PsiUtil.getArgumentTypes(argList, false, null); + + final PsiManager manager = index.getManager(); + final GlobalSearchScope resolveScope = index.getResolveScope(); + + if (PsiImplUtil.isSimpleArrayAccess(thisType, argTypes, manager, resolveScope)) { + return TypesUtil.boxPrimitiveType(((PsiArrayType)thisType).getComponentType(), manager, resolveScope); + } + + GroovyResolveResult candidate = PsiImplUtil.getIndexPropertyMethodCandidate(thisType, argTypes, index); + PsiType overloadedOperatorType = ResolveUtil.extractReturnTypeFromCandidate(candidate); + + PsiType componentType = extractMapValueType(thisType, argTypes, manager, resolveScope); + + if (overloadedOperatorType != null && + (componentType == null || !TypesUtil.isAssignable(overloadedOperatorType, componentType, manager, resolveScope))) { + return TypesUtil.boxPrimitiveType(overloadedOperatorType, manager, resolveScope); + } + return componentType; + } + + @Nullable + private PsiType extractMapValueType(PsiType thisType, PsiType[] argTypes, PsiManager manager, GlobalSearchScope resolveScope) { + if (argTypes.length != 1 || !InheritanceUtil.isInheritor(thisType, CommonClassNames.JAVA_UTIL_MAP)) return null; + final PsiType substituted = substituteTypeParameter(thisType, CommonClassNames.JAVA_UTIL_MAP, 1, true); + return TypesUtil.boxPrimitiveType(substituted, manager, resolveScope); + } + }; + public GrIndexPropertyImpl(@NotNull ASTNode node) { super(node); } @@ -65,44 +108,6 @@ public class GrIndexPropertyImpl extends GrExpressionImpl implements GrIndexProp } public PsiType getType() { - GrExpression selected = getSelectedExpression(); - PsiType thisType = selected.getType(); - - if (thisType == null) return null; - - GrArgumentList argList = getArgumentList(); - if (argList == null) return null; - - PsiType[] argTypes = PsiUtil.getArgumentTypes(argList, false, null); - - final PsiManager manager = getManager(); - final GlobalSearchScope resolveScope = getResolveScope(); - - if (PsiImplUtil.isSimpleArrayAccess(thisType, argTypes, manager, resolveScope)) { - return TypesUtil.boxPrimitiveType(((PsiArrayType)thisType).getComponentType(), manager, resolveScope); - } - - PsiType overloadedOperatorType = null; - GroovyResolveResult candidate = PsiImplUtil.getIndexPropertyMethodCandidate(thisType, argTypes, this); - - final PsiElement element = candidate.getElement(); - if (element instanceof PsiMethod) { - overloadedOperatorType = candidate.getSubstitutor().substitute(getSmartReturnType((PsiMethod)element)); - } - - PsiType componentType = extractMapValueType(thisType, argTypes); - - if (overloadedOperatorType != null && - (componentType == null || !TypesUtil.isAssignable(overloadedOperatorType, componentType, manager, resolveScope))) { - return TypesUtil.boxPrimitiveType(overloadedOperatorType, manager, resolveScope); - } - return componentType; - } - - @Nullable - private PsiType extractMapValueType(PsiType thisType, PsiType[] argTypes) { - if (argTypes.length != 1 || !InheritanceUtil.isInheritor(thisType, CommonClassNames.JAVA_UTIL_MAP)) return null; - final PsiType substituted = substituteTypeParameter(thisType, CommonClassNames.JAVA_UTIL_MAP, 1, true); - return TypesUtil.boxPrimitiveType(substituted, getManager(), getResolveScope()); + return GroovyPsiManager.getInstance(getProject()).getType(this, TYPE_CALCULATOR); } } \ No newline at end of file diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/types/GrSafeCastExpressionImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/types/GrSafeCastExpressionImpl.java index 05f54442c398..101a1e5b2954 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/types/GrSafeCastExpressionImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/types/GrSafeCastExpressionImpl.java @@ -21,14 +21,18 @@ import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.impl.source.resolve.ResolveCache; import com.intellij.util.ArrayUtil; +import com.intellij.util.Function; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.NullableFunction; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrSafeCastExpression; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement; +import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager; import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.GrExpressionImpl; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; @@ -38,6 +42,15 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUt */ public class GrSafeCastExpressionImpl extends GrExpressionImpl implements GrSafeCastExpression, PsiPolyVariantReference { + private static final Function TYPE_CALCULATOR = new NullableFunction() { + @Override + public PsiType fun(GrSafeCastExpressionImpl cast) { + GrTypeElement typeElement = cast.getCastTypeElement(); + if (typeElement != null) return TypesUtil.boxPrimitiveType(typeElement.getType(), cast.getManager(), cast.getResolveScope()); + return null; + } + }; + private static final class OurResolver implements ResolveCache.PolyVariantResolver { @Override public ResolveResult[] resolve(GrSafeCastExpressionImpl cast, boolean incompleteCode) { @@ -46,11 +59,13 @@ public class GrSafeCastExpressionImpl extends GrExpressionImpl implements GrSafe return GroovyResolveResult.EMPTY_ARRAY; } + final GrTypeElement typeElement = cast.getCastTypeElement(); + final PsiType toCast = typeElement == null ? null : typeElement.getType(); return TypesUtil.getOverloadedOperatorCandidates( type, GroovyTokenTypes.kAS, cast, - new PsiType[]{TypesUtil.createJavaLangClassType(cast.getCastTypeElement().getType(), cast.getProject(), cast.getResolveScope())} + new PsiType[]{TypesUtil.createJavaLangClassType(toCast, cast.getProject(), cast.getResolveScope())} ); } } @@ -70,17 +85,17 @@ public class GrSafeCastExpressionImpl extends GrExpressionImpl implements GrSafe } public PsiType getType() { - GrTypeElement typeElement = getCastTypeElement(); - if (typeElement != null) return TypesUtil.boxPrimitiveType(typeElement.getType(), getManager(), getResolveScope()); - return null; + return GroovyPsiManager.getInstance(getProject()).getType(this, TYPE_CALCULATOR); } + @Nullable public GrTypeElement getCastTypeElement() { return findChildByClass(GrTypeElement.class); } + @NotNull public GrExpression getOperand() { - return findChildByClass(GrExpression.class); + return findNotNullChildByClass(GrExpression.class); } @Override diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrClosureSignatureImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrClosureSignatureImpl.java index 39cdd09bafe5..dffa1b24dcb7 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrClosureSignatureImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrClosureSignatureImpl.java @@ -48,7 +48,7 @@ public class GrClosureSignatureImpl implements GrClosureSignature { mySubstitutor = substitutor; } - public GrClosureSignatureImpl(PsiParameter[] parameters, PsiType returnType) { + public GrClosureSignatureImpl(PsiParameter[] parameters, @Nullable PsiType returnType) { this(parameters, returnType, PsiSubstitutor.EMPTY); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrClosureSignatureUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrClosureSignatureUtil.java index 71272388901e..c97be457a42e 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrClosureSignatureUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrClosureSignatureUtil.java @@ -119,7 +119,7 @@ public class GrClosureSignatureUtil { }; } - public static GrClosureSignature createSignature(PsiParameter[] parameters, PsiType returnType) { + public static GrClosureSignature createSignature(PsiParameter[] parameters, @Nullable PsiType returnType) { return new GrClosureSignatureImpl(parameters, returnType); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java index 5b2be689e35a..2f28deb57d8c 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java @@ -26,6 +26,9 @@ import com.intellij.psi.scope.JavaScopeProcessorEvent; import com.intellij.psi.scope.NameHint; import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.util.*; +import com.intellij.psi.util.PsiUtil; +import com.intellij.util.ArrayUtil; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.dsl.GroovyDslFileIndex; @@ -46,16 +49,18 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefini import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrGdkMethod; 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.api.types.GrClosureSignature; +import org.jetbrains.plugins.groovy.lang.psi.impl.GrClosureType; import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyResolveResultImpl; -import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames; -import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassResolverProcessor; -import org.jetbrains.plugins.groovy.lang.resolve.processors.MethodResolverProcessor; -import org.jetbrains.plugins.groovy.lang.resolve.processors.PropertyResolverProcessor; -import org.jetbrains.plugins.groovy.lang.resolve.processors.ResolverProcessor; +import org.jetbrains.plugins.groovy.lang.psi.impl.types.GrClosureSignatureUtil; +import org.jetbrains.plugins.groovy.lang.psi.util.*; +import org.jetbrains.plugins.groovy.lang.resolve.processors.*; import java.util.*; import java.util.concurrent.ConcurrentHashMap; +import static org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil.getSmartReturnType; + /** * @author ven */ @@ -405,7 +410,7 @@ public class ResolveUtil { return elements; } - public static GroovyResolveResult[] filterSameSignatureCandidates(Collection candidates, int argumentCount) { + public static GroovyResolveResult[] filterSameSignatureCandidates(Collection candidates) { GroovyResolveResult[] array = candidates.toArray(new GroovyResolveResult[candidates.size()]); if (array.length == 1) return array; @@ -533,10 +538,6 @@ public class ResolveUtil { return false; } - public static boolean isInWithContext(GroovyResolveResult resolveResult) { - return isInWithContext(resolveResult.getCurrentFileResolveContext()); - } - public static boolean isInWithContext(GroovyPsiElement resolveContext) { if (resolveContext instanceof GrExpression) { final PsiElement parent = resolveContext.getParent(); @@ -586,27 +587,115 @@ public class ResolveUtil { @Nullable String methodName, @NotNull GroovyPsiElement place, @Nullable PsiType... argumentTypes) { - if (methodName != null) { - MethodResolverProcessor processor = - new MethodResolverProcessor(methodName, place, false, thisType, argumentTypes, PsiType.EMPTY_ARRAY); - final ResolveState state; - if (thisType instanceof PsiClassType) { - final PsiClassType classtype = (PsiClassType)thisType; - final PsiClassType.ClassResolveResult resolveResult = classtype.resolveGenerics(); - final PsiClass lClass = resolveResult.getElement(); - state = ResolveState.initial().put(PsiSubstitutor.KEY, resolveResult.getSubstitutor()); - if (lClass != null) { - lClass.processDeclarations(processor, state, null, place); + if (methodName == null) return GroovyResolveResult.EMPTY_ARRAY; + + MethodResolverProcessor processor = + new MethodResolverProcessor(methodName, place, false, thisType, argumentTypes, PsiType.EMPTY_ARRAY); + processCandidatesInner(thisType, place, processor); + boolean hasApplicableMethods = processor.hasApplicableCandidates(); + final GroovyResolveResult[] methodCandidates = processor.getCandidates(); + if (hasApplicableMethods && methodCandidates.length == 1) return methodCandidates; + + PropertyResolverProcessor propertyResolver = new PropertyResolverProcessor(methodName, place); + processCandidatesInner(thisType, place, propertyResolver); + final GroovyResolveResult[] allPropertyCandidates = propertyResolver.getCandidates(); + + List propertyCandidates = new ArrayList(allPropertyCandidates.length); + for (GroovyResolveResult candidate : allPropertyCandidates) { + final PsiElement resolved = candidate.getElement(); + if (!(resolved instanceof GrField)) continue; + final PsiType type = ((GrField)resolved).getTypeGroovy(); + if (isApplicableClosureType(type, argumentTypes, place)) { + propertyCandidates.add(candidate); + } + } + + for (GroovyResolveResult candidate : propertyCandidates) { + final PsiElement element = candidate.getElement(); + if (element instanceof GrField) { + final PsiClass containingClass = ((PsiField)element).getContainingClass(); + if (containingClass != null && PsiTreeUtil.isContextAncestor(containingClass, place, true)) { + return new GroovyResolveResult[]{candidate}; } } - else { - state = ResolveState.initial(); - } + } - processNonCodeMethods(thisType, processor, place, state); - processCategoryMembers(place, processor); - return processor.getCandidates(); + List allCandidates = new ArrayList(); + if (hasApplicableMethods) { + ContainerUtil.addAll(allCandidates, methodCandidates); + } + ContainerUtil.addAll(allCandidates, propertyCandidates); + + //search for getters + for (String getterName : GroovyPropertyUtils.suggestGettersName(methodName)) { + AccessorResolverProcessor getterResolver = new AccessorResolverProcessor(getterName, place, true); + processCandidatesInner(thisType, place, getterResolver); + final GroovyResolveResult[] candidates = getterResolver.getCandidates(); //can be only one candidate + final List applicable = new ArrayList(); + for (GroovyResolveResult candidate : candidates) { + final PsiType type = getSmartReturnType((PsiMethod)candidate.getElement()); + if (isApplicableClosureType(type, argumentTypes, place)) { + applicable.add(candidate); + } + } + if (applicable.size() == 1) { + return applicable.toArray(new GroovyResolveResult[applicable.size()]); + } + ContainerUtil.addAll(allCandidates, applicable); + } + + if (allCandidates.size() > 0) { + return allCandidates.toArray(new GroovyResolveResult[allCandidates.size()]); } return GroovyResolveResult.EMPTY_ARRAY; } + + private static boolean isApplicableClosureType(PsiType type, PsiType[] argTypes, GroovyPsiElement place) { + if (!(type instanceof GrClosureType)) return false; + + final GrClosureSignature signature = ((GrClosureType)type).getSignature(); + return GrClosureSignatureUtil.isSignatureApplicable(signature, argTypes, place); + } + + private static void processCandidatesInner(PsiType thisType, GroovyPsiElement place, ResolverProcessor processor) { + final ResolveState state; + if (thisType instanceof PsiClassType) { + final PsiClassType classtype = (PsiClassType)thisType; + final PsiClassType.ClassResolveResult resolveResult = classtype.resolveGenerics(); + final PsiClass lClass = resolveResult.getElement(); + state = ResolveState.initial().put(PsiSubstitutor.KEY, resolveResult.getSubstitutor()); + if (lClass != null) { + lClass.processDeclarations(processor, state, null, place); + } + } + else { + state = ResolveState.initial(); + } + + processNonCodeMethods(thisType, processor, place, state); + processCategoryMembers(place, processor); + } + + @Nullable + public static PsiType extractReturnTypeFromCandidate(GroovyResolveResult candidate) { + final PsiElement element = candidate.getElement(); + if (element instanceof PsiMethod && !candidate.isInvokedOnProperty()) { + return candidate.getSubstitutor().substitute(getSmartReturnType((PsiMethod)element)); + } + + final PsiType type; + if (element instanceof GrField) { + type = ((GrField)element).getTypeGroovy(); + } + else if (element instanceof PsiMethod) { + type = getSmartReturnType((PsiMethod)element); + } + else { + return null; + } + if (type instanceof GrClosureType) { + return candidate.getSubstitutor().substitute(((GrClosureType)type).getSignature().getReturnType()); + } + return null; + } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/processors/CompletionProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/processors/CompletionProcessor.java index 6675e16f2668..699f94697fb7 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/processors/CompletionProcessor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/processors/CompletionProcessor.java @@ -57,6 +57,6 @@ public class CompletionProcessor extends ResolverProcessor { @NotNull public GroovyResolveResult[] getCandidates() { if (!super.hasCandidates()) return GroovyResolveResult.EMPTY_ARRAY; - return ResolveUtil.filterSameSignatureCandidates(getCandidatesInternal(), -1); + return ResolveUtil.filterSameSignatureCandidates(getCandidatesInternal()); } } \ No newline at end of file diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/processors/MethodResolverProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/processors/MethodResolverProcessor.java index 2a2350173575..dfa830e0609d 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/processors/MethodResolverProcessor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/processors/MethodResolverProcessor.java @@ -249,7 +249,7 @@ public class MethodResolverProcessor extends ResolverProcessor { if (!myInapplicableCandidates.isEmpty()) { final Set resultSet = myAllVariants ? myInapplicableCandidates : filterCorrectParameterCount(myInapplicableCandidates); - return ResolveUtil.filterSameSignatureCandidates(resultSet, myArgumentTypes != null ? myArgumentTypes.length : -1); + return ResolveUtil.filterSameSignatureCandidates(resultSet); } return GroovyResolveResult.EMPTY_ARRAY; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyRefactoringUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyRefactoringUtil.java index f4d17aa06754..b434373731a2 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyRefactoringUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyRefactoringUtil.java @@ -632,7 +632,10 @@ public abstract class GroovyRefactoringUtil { argText.append(argument.getText()).append(", "); argument.delete(); } - argText.replace(argText.length() - 2, argText.length(), "]"); + if (arguments.size() > 0) { + argText.delete(argText.length() - 2, argText.length()); + } + argText.append("]"); if (type instanceof PsiArrayType) { type = substitutor.substitute(type); String typeText = type.getCanonicalText(); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/CodeBlockGenerator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/CodeBlockGenerator.java index a7197c918cc3..8f1b931b28da 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/CodeBlockGenerator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/CodeBlockGenerator.java @@ -17,10 +17,8 @@ package org.jetbrains.plugins.groovy.refactoring.convertToJava; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; -import com.intellij.psi.CommonClassNames; -import com.intellij.psi.JavaPsiFacade; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiType; +import com.intellij.psi.*; +import com.intellij.util.containers.hash.HashSet; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrCondition; @@ -31,18 +29,18 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.*; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrAssertStatement; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrFlowInterruptingStatement; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrReturnStatement; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrThrowStatement; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.*; import org.jetbrains.plugins.groovy.lang.psi.api.statements.clauses.GrForClause; import org.jetbrains.plugins.groovy.lang.psi.api.statements.clauses.GrForInClause; import org.jetbrains.plugins.groovy.lang.psi.api.statements.clauses.GrTraditionalForClause; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrApplicationStatement; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement; +import java.util.Set; + /** * @author Maxim.Medvedev */ @@ -51,28 +49,15 @@ public class CodeBlockGenerator extends Generator { private final StringBuilder builder; private static final Logger LOG = Logger.getInstance("#org.jetbrains.plugins.groovy.refactoring.convertToJava.CodeBlockGenerator"); - private final boolean insertStatementsFromExpr; - private final ExpressionContext context; - public CodeBlockGenerator(StringBuilder builder, Project project) { - this(builder, project, false); - } - - public CodeBlockGenerator(StringBuilder builder, Project project, boolean insertStatementsFromExpr) { - this(builder, insertStatementsFromExpr, new ExpressionContext(project)); - } - - public CodeBlockGenerator(StringBuilder builder, - boolean insertStatementsFromExpr, - ExpressionContext context) { + public CodeBlockGenerator(StringBuilder builder, ExpressionContext context) { this.builder = builder; - this.insertStatementsFromExpr = insertStatementsFromExpr; this.context = context; } - public CodeBlockGenerator(StringBuilder builder, ExpressionContext context) { - this(builder, false, context); + public CodeBlockGenerator(StringBuilder builder, Project project) { + this(builder, new ExpressionContext(project)); } @Override @@ -88,13 +73,16 @@ public class CodeBlockGenerator extends Generator { @Override public void visitOpenBlock(GrOpenBlock block) { builder.append("{\n"); - super.visitOpenBlock(block); + final GrStatement[] statements = block.getStatements(); + for (GrStatement statement : statements) { + statement.accept(this); + builder.append('\n'); + } builder.append("}\n"); } - @Override public void visitStatement(GrStatement statement) { - super.visitStatement(statement); //To change body of overridden methods use File | Settings | File Templates. + LOG.assertTrue(false, "all statements must be overloaded"); } @Override @@ -126,32 +114,10 @@ public class CodeBlockGenerator extends Generator { writeStatement(statementBuilder, statement, null); } - private void writeStatement(StringBuilder statementBuilder, GrStatement statement, @Nullable ExpressionContext context) { - final PsiElement parent = statement.getParent(); - - final boolean addParentheses = - insertStatementsFromExpr && context != null && context.myStatements.size() > 0 && parent instanceof GrControlStatement; - if (addParentheses) { - builder.append("{\n"); - } - - if (insertStatementsFromExpr) { - if (context != null) { - for (String st : context.myStatements) { - builder.append(st).append("\n"); - } - } - } - else { - LOG.assertTrue(context != null); - LOG.assertTrue(context.myStatements.size() == 0); - context.myStatements.addAll(context.myStatements); - } - - builder.append(statementBuilder); - if (addParentheses) { - builder.append("}\n"); - } + private void writeStatement(StringBuilder statementBuilder, + GrStatement statement, + @Nullable ExpressionContext context) { + GenerationUtil.writeStatement(builder, statementBuilder, statement, context); } @Override @@ -191,9 +157,15 @@ public class CodeBlockGenerator extends Generator { final StringBuilder statementBuilder = new StringBuilder(); final ExpressionContext context = new ExpressionContext(this.context.project, this.context.myUsedVarNames); expression.accept(new ExpressionGenerator(statementBuilder, context)); + statementBuilder.append(";"); writeStatement(statementBuilder, expression, context); } + @Override + public void visitApplicationStatement(GrApplicationStatement applicationStatement) { + visitExpression(applicationStatement); + } + @Override public void visitTypeDefinition(GrTypeDefinition typeDefinition) { //todo ??????? @@ -222,6 +194,7 @@ public class CodeBlockGenerator extends Generator { @Override public void visitForStatement(GrForStatement forStatement) { final StringBuilder builder = new StringBuilder(); + builder.append("for("); final GrForClause clause = forStatement.getClause(); ExpressionContext forContext = context.extend(); @@ -230,16 +203,14 @@ public class CodeBlockGenerator extends Generator { final GrVariable declaredVariable = clause.getDeclaredVariable(); LOG.assertTrue(declaredVariable != null); - builder.append("for("); - writeVariableWithoutColon(builder, declaredVariable); + writeVariableWithoutSemicolonAndInitializer(builder, declaredVariable); builder.append(" : "); if (expression != null) { final ExpressionContext context = forContext.copy(); expression.accept(new ExpressionGenerator(builder, context)); } - builder.append(")"); } - else { + else if (clause instanceof GrTraditionalForClause) { final GrTraditionalForClause cl = (GrTraditionalForClause)clause; final GrCondition initialization = cl.getInitialization(); final GrExpression condition = cl.getCondition(); @@ -247,7 +218,7 @@ public class CodeBlockGenerator extends Generator { if (initialization instanceof GrParameter) { StringBuilder partBuilder = new StringBuilder(); - writeVariableWithoutColon(partBuilder, (GrParameter)initialization); + writeVariableWithoutSemicolonAndInitializer(partBuilder, (GrParameter)initialization); final GrExpression initializer = ((GrParameter)initialization).getDefaultInitializer(); if (initializer != null) { final ExpressionContext partContext = forContext.copy(); @@ -275,10 +246,13 @@ public class CodeBlockGenerator extends Generator { if (update != null) { genForPart(builder, update, forContext.copy()); } - builder.append(")"); } + builder.append(")"); - forStatement.getBody().accept(new CodeBlockGenerator(builder, forContext)); + final GrStatement body = forStatement.getBody(); + if (body != null) { + body.accept(new CodeBlockGenerator(builder, forContext)); + } } private static void genForPart(StringBuilder builder, GrExpression part, final ExpressionContext context) { @@ -293,11 +267,11 @@ public class CodeBlockGenerator extends Generator { builder.append(visitor.getBuilder()); } - private static void writeVariableWithoutColon(StringBuilder builder, GrVariable var) { - if (GenerationUtil.writeModifiers(builder, var.getModifierList(), GenerationUtil.JAVA_MODIFIERS)) { + private static void writeVariableWithoutSemicolonAndInitializer(StringBuilder builder, GrVariable var) { + if (GenerationUtil.writeModifiers(builder, var.getModifierList())) { builder.append(" "); } - GenerationUtil.writeType(builder, var.getDeclaredType()); + GenerationUtil.writeType(builder, getVarType(var)); builder.append(" ").append(var.getName()); } @@ -321,7 +295,10 @@ public class CodeBlockGenerator extends Generator { @Override public void visitSwitchStatement(GrSwitchStatement switchStatement) { - //todo + final StringBuilder builder = new StringBuilder(); + final ExpressionContext copy = context.copy(); + SwitchStatementGenerator.generate(builder, copy, switchStatement); + writeStatement(builder, switchStatement, copy); } @Override @@ -343,7 +320,7 @@ public class CodeBlockGenerator extends Generator { public void visitCatchClause(GrCatchClause catchClause) { final GrParameter parameter = catchClause.getParameter(); builder.append("catch ("); - writeVariableWithoutColon(builder, parameter); + writeVariableWithoutSemicolonAndInitializer(builder, parameter); builder.append(") "); final GrOpenBlock body = catchClause.getBody(); if (body != null) { @@ -379,58 +356,145 @@ public class CodeBlockGenerator extends Generator { @Override public void visitVariableDeclaration(GrVariableDeclaration variableDeclaration) { - final GrModifierList modifierList = variableDeclaration.getModifierList(); - final GrVariable[] variables = variableDeclaration.getVariables(); StringBuilder builder = new StringBuilder(); ExpressionContext expressionContext = context.copy(); - final ExpressionGenerator expressionGenerator = new ExpressionGenerator(builder, expressionContext); if (variableDeclaration.isTuple()) { - final GrTupleDeclaration tuple = variableDeclaration.getTupleDeclaration(); - final GrExpression tupleInitializer = tuple.getInitializerGroovy(); - if (tupleInitializer instanceof GrListOrMap) { - final GrExpression[] initializers = ((GrListOrMap)tupleInitializer).getInitializers(); - for (int i = 0; i < variables.length; i++) { - final GrVariable v = variables[i]; - final PsiType type = v.getDeclaredType(); - GenerationUtil.writeModifiers(builder, modifierList); - GenerationUtil.writeType(builder, type); - builder.append(" ").append(v.getName()); - if (i < initializers.length) { - builder.append(" = "); - initializers[i].accept(expressionGenerator); + writeTupleDeclaration(variableDeclaration, builder, expressionContext); + } + else { + writeSimpleVarDeclaration(variableDeclaration, builder, expressionContext); + } + + writeStatement(builder, variableDeclaration, expressionContext); + } + + private static void writeSimpleVarDeclaration(GrVariableDeclaration variableDeclaration, + StringBuilder builder, + ExpressionContext expressionContext) { + GrVariable[] variables = variableDeclaration.getVariables(); + + final GrTypeElement typeElement = variableDeclaration.getTypeElementGroovy(); + PsiType type = null; + Set types = new HashSet(variables.length); + if (typeElement == null) { + if (variables.length > 1) { + for (GrVariable variable : variables) { + final GrExpression initializer = variable.getInitializerGroovy(); + if (initializer != null) { + final PsiType varType = initializer.getType(); + if (varType != null) { + types.add(getTypeText(varType)); + type = varType; + } } - builder.append(";\n"); + } + if (type == null) { + type = PsiType.getJavaLangObject(variableDeclaration.getManager(), variableDeclaration.getResolveScope()); } } else { - final PsiType iteratorType = - JavaPsiFacade.getElementFactory(context.project).createTypeFromText(CommonClassNames.JAVA_UTIL_ITERATOR, variableDeclaration); - final String iteratorName = GenerationUtil.suggestVarName(iteratorType, variableDeclaration, expressionContext); - builder.append("final ").append(CommonClassNames.JAVA_UTIL_ITERATOR).append(" ").append(iteratorName).append(" = "); - - GenerationUtil.invokeMethodByName(tupleInitializer, "iterator", GrExpression.EMPTY_ARRAY, GrNamedArgument.EMPTY_ARRAY, - GrClosableBlock.EMPTY_ARRAY, expressionGenerator, variableDeclaration); - for (final GrVariable v : variables) { - GenerationUtil.writeModifiers(builder, modifierList); - final PsiType type = v.getDeclaredType(); - GenerationUtil.writeType(builder, type); - builder.append(" ").append(v.getName()); - builder.append(" = ").append(iteratorName).append(".hasNext() ? ").append(iteratorName).append(".next() : null;"); - } + type = getVarType(variables[0]); } } else { - GenerationUtil.writeModifiers(builder, modifierList); - final GrTypeElement typeElement = variableDeclaration.getTypeElementGroovy(); - PsiType type = typeElement == null - ? PsiType.getJavaLangObject(variableDeclaration.getManager(), variableDeclaration.getResolveScope()) - : typeElement.getType(); - GenerationUtil.writeType(builder, type); + type = typeElement.getType(); } - writeStatement(builder, variableDeclaration, expressionContext); + + if (types.size() > 1) { + if (variableDeclaration.getParent() instanceof GrControlStatement) { + expressionContext.setInsertCurlyBrackets(); + } + for (GrVariable variable : variables) { + writeVariableSeparately(variable, builder, expressionContext); + builder.append(";\n"); + } + return; + } + + GenerationUtil.writeType(builder, type); + + builder.append(" "); + for (GrVariable variable : variables) { + writeVariableWithoutType(builder, expressionContext, variable); + builder.append(", "); + } + if (variables.length > 0) { + builder.delete(builder.length() - 2, builder.length()); + } + builder.append(";"); + } + + private static void writeVariableWithoutType(StringBuilder builder, ExpressionContext expressionContext, GrVariable variable) { + builder.append(variable.getName()); + final GrExpression initializer = variable.getInitializerGroovy(); + if (initializer != null) { + builder.append(" = "); + initializer.accept(new ExpressionGenerator(builder, expressionContext)); + } + } + + private static void writeVariableSeparately(GrVariable variable, StringBuilder builder, ExpressionContext expressionContext) { + PsiType type = getVarType(variable); + + if (GenerationUtil.writeModifiers(builder, variable.getModifierList())) { + builder.append(" "); + } + + GenerationUtil.writeType(builder, type); + builder.append(" "); + + writeVariableWithoutType(builder, expressionContext, variable); + } + + private static PsiType getVarType(GrVariable variable) { + PsiType type = variable.getDeclaredType(); + if (type == null) { + type = variable.getTypeGroovy(); + } + if (type == null) { + type = variable.getType(); + } + return type; + } + + private void writeTupleDeclaration(GrVariableDeclaration variableDeclaration, + StringBuilder builder, + ExpressionContext expressionContext) { + GrVariable[] variables = variableDeclaration.getVariables(); + final GrExpression tupleInitializer = variableDeclaration.getTupleDeclaration().getInitializerGroovy(); + if (tupleInitializer instanceof GrListOrMap) { + for (GrVariable variable : variables) { + writeVariableSeparately(variable, builder, expressionContext); + builder.append(";\n"); + } + } + else { + final PsiType iteratorType = + JavaPsiFacade.getElementFactory(context.project).createTypeFromText(CommonClassNames.JAVA_UTIL_ITERATOR, variableDeclaration); + final String iteratorName = GenerationUtil.suggestVarName(iteratorType, variableDeclaration, expressionContext); + builder.append("final ").append(CommonClassNames.JAVA_UTIL_ITERATOR).append(" ").append(iteratorName).append(" = "); + + GenerationUtil.invokeMethodByName(tupleInitializer, "iterator", GrExpression.EMPTY_ARRAY, GrNamedArgument.EMPTY_ARRAY, + GrClosableBlock.EMPTY_ARRAY, new ExpressionGenerator(builder, expressionContext), + variableDeclaration); + final GrModifierList modifierList = variableDeclaration.getModifierList(); + for (final GrVariable v : variables) { + GenerationUtil.writeModifiers(builder, modifierList); + final PsiType type = getVarType(v); + GenerationUtil.writeType(builder, type); + builder.append(" ").append(v.getName()); + builder.append(" = ").append(iteratorName).append(".hasNext() ? ").append(iteratorName).append(".next() : null;"); + } + } + } + + private static String getTypeText(PsiType varType) { + final StringBuilder builder = new StringBuilder(); + GenerationUtil.writeType(builder, varType); + return builder.toString(); } @Override diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ConvertToJavaHandler.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ConvertToJavaHandler.java index 48ab2035e270..cde84e1bedf7 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ConvertToJavaHandler.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ConvertToJavaHandler.java @@ -49,7 +49,7 @@ public class ConvertToJavaHandler implements RefactoringActionHandler { invokeInner(project, elements, editor); } - private void invokeInner(Project project, PsiElement[] elements, Editor editor) { + private static void invokeInner(Project project, PsiElement[] elements, Editor editor) { for (PsiElement element : elements) { if (!(element instanceof GroovyFile)) { if (!ApplicationManager.getApplication().isUnitTestMode()) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ConvertToJavaProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ConvertToJavaProcessor.java index 8a4dca3074d9..c4eeebae5882 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ConvertToJavaProcessor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ConvertToJavaProcessor.java @@ -16,13 +16,10 @@ package org.jetbrains.plugins.groovy.refactoring.convertToJava; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Document; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.PsiDirectory; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiFileFactory; +import com.intellij.psi.*; import com.intellij.refactoring.BaseRefactoringProcessor; import com.intellij.refactoring.ui.UsageViewDescriptorAdapter; import com.intellij.usageView.UsageInfo; @@ -30,10 +27,9 @@ import com.intellij.usageView.UsageViewDescriptor; import com.intellij.util.containers.hash.HashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; +import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.GrTopStatement; import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringBundle; -import java.util.Collections; -import java.util.Map; import java.util.Set; /** @@ -73,35 +69,44 @@ public class ConvertToJavaProcessor extends BaseRefactoringProcessor { //private static String @Override protected void performRefactoring(UsageInfo[] usages) { - final GroovyToJavaGenerator generator = new GroovyToJavaGenerator(myProject, Collections.emptyList(), true); - final PsiFileFactory fileFactory = PsiFileFactory.getInstance(myProject); +// final GroovyToJavaGenerator generator = new GroovyToJavaGenerator(myProject, Collections.emptyList(), true); - PsiFile fileToOpen = null; for (GroovyFile file : myFiles) { final PsiDirectory dir = file.getContainingDirectory(); LOG.assertTrue(dir != null); - final Map fileMap = generator.generateStubs(file); - for (String fileName : fileMap.keySet()) { - file.delete(); - final PsiFile[] files = dir.getFiles(); - Set fileNames = new HashSet(); - for (PsiFile psiFile : files) { - fileNames.add(psiFile.getName()); - } - int index = 0; - String prefix = FileUtil.getNameWithoutExtension(fileName); - while (fileNames.contains(fileName)) { - fileName = prefix + index + ".java"; - } - - final PsiFile newFile = fileFactory.createFileFromText(fileName, fileMap.get(fileName)); - dir.add(newFile); + final PsiFile[] files = dir.getFiles(); + Set fileNames = new HashSet(); + for (PsiFile psiFile : files) { + fileNames.add(psiFile.getName()); } + String prefix = FileUtil.getNameWithoutExtension(file.getName()); + String fileName = prefix + ".java"; + int index = 1; + while (fileNames.contains(fileName)) { + fileName = prefix + index + ".java"; + } + final Project project = file.getProject(); + + GrTopStatement[] statements = file.getTopStatements(); + final StringBuilder builder = new StringBuilder(); + CodeBlockGenerator generator = new CodeBlockGenerator(builder, new ExpressionContext(project)); + for (GrTopStatement statement : statements) { + statement.accept(generator); + builder.append("\n"); + } + + final PsiFile newFile = (PsiFile)file.setName(fileName); + final Document document = PsiDocumentManager.getInstance(project).getDocument(newFile); + document.setText(builder); + /*final PsiFile created = PsiFileFactory.getInstance(project) + .createFileFromText(file.getScriptClass().getName() + ".java", StdLanguages.JAVA, builder.toString()); + PostprocessReformattingAspect.getInstance(project).doPostponedFormatting(); + file.delete(); + dir.add(created);*/ + //QuickfixUtil.positionCursor(project, created, created.getFirstChild()); } - - } @Override diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ExpressionContext.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ExpressionContext.java index 01a04fa9b598..a333b55290de 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ExpressionContext.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ExpressionContext.java @@ -26,6 +26,7 @@ class ExpressionContext { List myStatements = new ArrayList(); Set myUsedVarNames; Project project; + private boolean myShouldInsertCurlyBrackets = false; ExpressionContext(Project project, Set usedVarNames) { this.project = project; @@ -45,4 +46,12 @@ class ExpressionContext { usedVarNames.addAll(myUsedVarNames); return new ExpressionContext(project, usedVarNames); } + + public void setInsertCurlyBrackets() { + myShouldInsertCurlyBrackets = true; + } + + public boolean shouldInsertCurlyBrackets() { + return myShouldInsertCurlyBrackets; + } } \ No newline at end of file diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ExpressionGenerator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ExpressionGenerator.java index 3b249bbde3a3..babcf42555e9 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ExpressionGenerator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ExpressionGenerator.java @@ -17,20 +17,21 @@ package org.jetbrains.plugins.groovy.refactoring.convertToJava; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.tree.IElementType; -import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.intentions.conversions.ConvertGStringToStringIntention; +import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory; -import org.jetbrains.plugins.groovy.lang.psi.GroovyRecursiveElementVisitor; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap; import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifier; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrConstructorInvocation; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableDeclaration; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentLabel; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; @@ -60,7 +61,7 @@ import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringUtil; -import java.util.*; +import static org.jetbrains.plugins.groovy.refactoring.convertToJava.GenerationUtil.*; /** * @author Maxim.Medvedev @@ -130,7 +131,7 @@ public class ExpressionGenerator extends Generator { } } - GenerationUtil.invokeMethodByName(invoked, "call", exprs, namedArgs, clArgs, this, methodCallExpression); + invokeMethodByName(invoked, "call", exprs, namedArgs, clArgs, this, methodCallExpression); } @Override @@ -142,8 +143,8 @@ public class ExpressionGenerator extends Generator { final String varName; if (hasFieldInitialization) { builder = new StringBuilder(); - varName = GenerationUtil.suggestVarName(type, newExpression, this.context); - GenerationUtil.writeType(builder, type); + varName = suggestVarName(type, newExpression, this.context); + writeType(builder, type); builder.append(" ").append(varName).append(" = "); } else { @@ -166,10 +167,10 @@ public class ExpressionGenerator extends Generator { final PsiType builtIn = typeElement.getType(); LOG.assertTrue(builtIn instanceof PsiPrimitiveType); final PsiType boxed = TypesUtil.boxPrimitiveType(builtIn, newExpression.getManager(), newExpression.getResolveScope()); - GenerationUtil.writeType(builder, boxed); + writeType(builder, boxed); } else if (referenceElement != null) { - GenerationUtil.writeCodeReferenceElement(builder, referenceElement); + writeCodeReferenceElement(builder, referenceElement); } final GrArgumentList argList = newExpression.getArgumentList(); @@ -261,7 +262,7 @@ public class ExpressionGenerator extends Generator { private static boolean hasFieldInitialization(GrNewExpression newExpression) { final GrArgumentList argumentList = newExpression.getArgumentList(); if (argumentList == null) return false; - if (argumentList.getNamedArguments().length > 0) return false; + if (argumentList.getNamedArguments().length == 0) return false; final GrCodeReferenceElement refElement = newExpression.getReferenceElement(); if (refElement == null) return false; @@ -277,7 +278,7 @@ public class ExpressionGenerator extends Generator { } private void writeTypeBody(StringBuilder builder, GrAnonymousClassDefinition anonymous) { - //todo + //todo write type body for anonymous class throw new UnsupportedOperationException(); } @@ -324,13 +325,55 @@ public class ExpressionGenerator extends Generator { @Override public void visitAssignmentExpression(GrAssignmentExpression expression) { - //todo + final GrExpression lValue = expression.getLValue(); + GrExpression rValue = expression.getRValue(); + final IElementType token = expression.getOperationToken(); + + + if (token == GroovyTokenTypes.mASSIGN) { + lValue.accept(this); + builder.append(" = "); + if (rValue != null) { + rValue.accept(this); + } + return; + } + + final GroovyResolveResult resolveResult = PsiImplUtil.extractUniqueResult(expression.multiResolve(false)); + final PsiElement resolved = resolveResult.getElement(); + + if (resolved instanceof PsiMethod) { + lValue.accept(this); + builder.append(" = "); + if (rValue == null) { + rValue = factory.createExpressionFromText("null"); + } + invokeMethodOn( + ((PsiMethod)resolved), + lValue, + new GrExpression[]{rValue}, + GrNamedArgument.EMPTY_ARRAY, + GrClosableBlock.EMPTY_ARRAY, + resolveResult.getSubstitutor(), + expression + ); + } + else { + writeSimpleBinaryExpression(expression.getOpToken(), lValue, rValue); + } } @Override public void visitBinaryExpression(GrBinaryExpression expression) { final GrExpression left = expression.getLeftOperand(); GrExpression right = expression.getRightOperand(); + final PsiType ltype = left.getType(); + if (GenerationSettings.dontReplaceOperatorsWithMethodsForNumbers && + (TypesUtil.isNumericType(ltype) && (right == null || TypesUtil.isNumericType(right.getType())) || + ltype != null && TypesUtil.typeEqualsToText(ltype, CommonClassNames.JAVA_LANG_STRING))) { + writeSimpleBinaryExpression(expression.getOperationToken(), left, right); + return; + } final GroovyResolveResult resolveResult = PsiImplUtil.extractUniqueResult(expression.multiResolve(false)); final PsiElement resolved = resolveResult.getElement(); @@ -349,11 +392,17 @@ public class ExpressionGenerator extends Generator { ); } else { - left.accept(this); - builder.append(expression.getOperationToken().getText()); - if (right != null) { - right.accept(this); - } + writeSimpleBinaryExpression(expression.getOperationToken(), left, right); + } + } + + private void writeSimpleBinaryExpression(PsiElement opToken, GrExpression left, GrExpression right) { + left.accept(this); + builder.append(" "); + builder.append(opToken.getText()); + if (right != null) { + builder.append(" "); + right.accept(this); } } @@ -408,8 +457,14 @@ public class ExpressionGenerator extends Generator { else { value = literal.getValue(); } + if (value instanceof String) { + builder.append('"').append(StringUtil.escapeQuotes((String)value)).append('"'); + } + else { + builder.append(value); + } - //todo + //todo replace with character in some cases } @Override @@ -421,16 +476,70 @@ public class ExpressionGenerator extends Generator { @Override public void visitReferenceExpression(GrReferenceExpression referenceExpression) { - final GrExpression qualifier = referenceExpression.getQualifier(); - final PsiElement refNameElement = referenceExpression.getReferenceNameElement(); - final GroovyResolveResult resolveResult = referenceExpression.advancedResolve(); + LOG.assertTrue(!(referenceExpression.getParent() instanceof GrMethodCall)); - if (qualifier != null) { - qualifier.accept(this); - builder.append("."); + final GrExpression qualifier = referenceExpression.getQualifier(); + final GroovyResolveResult resolveResult = referenceExpression.advancedResolve(); + final PsiElement resolved = resolveResult.getElement(); + + final IElementType type = referenceExpression.getDotTokenType(); + + GrExpression qualifierToUse = qualifier; + + if (type == GroovyTokenTypes.mOPTIONAL_DOT) { + LOG.assertTrue(qualifier != null); + + String qualifierName = createVarByInitializer(qualifier); + builder.append(qualifierName).append(" == null ? null : "); + + qualifierToUse = factory.createReferenceExpressionFromText(qualifierName, referenceExpression); } - builder.append(referenceExpression.getReferenceName()); - //todo make reference expression + + + if (resolveResult.isInvokedOnProperty()) { + LOG.assertTrue(resolved instanceof PsiMethod); + invokeMethodOn( + ((PsiMethod)resolved), + qualifierToUse, + GrExpression.EMPTY_ARRAY, + GrNamedArgument.EMPTY_ARRAY, + GrClosableBlock.EMPTY_ARRAY, + resolveResult.getSubstitutor(), + referenceExpression + ); + } + else { + if (qualifierToUse != null) { + qualifierToUse.accept(this); + builder.append('.'); + } + final String refName = + resolved instanceof PsiNamedElement ? ((PsiNamedElement)resolved).getName() : referenceExpression.getReferenceName(); + builder.append(refName); + } + } + + private String createVarByInitializer(GrExpression initializer) { + if (initializer instanceof GrReferenceExpression) { + final GrExpression qualifier = ((GrReferenceExpression)initializer).getQualifier(); + if (qualifier == null) { + final PsiElement resolved = ((GrReferenceExpression)initializer).resolve(); + if (resolved instanceof GrVariable && GroovyRefactoringUtil.isLocalVariable((GrVariable)resolved)) { + + //don't create new var. it is already exists + return ((GrVariable)resolved).getName(); + } + } + } + final String name = suggestVarName(initializer, context); + final StringBuilder builder = new StringBuilder(); + builder.append("final "); + writeType(builder, initializer.getType()); + builder.append(' ').append(name).append(" = "); + initializer.accept(new ExpressionGenerator(builder, context)); + builder.append(';'); + context.myStatements.add(builder.toString()); + return name; } @Override @@ -440,14 +549,8 @@ public class ExpressionGenerator extends Generator { final PsiElement resolved = expr.resolve(); LOG.assertTrue(resolved instanceof PsiClass); - final PsiElement firstContainingClass = PsiTreeUtil.getParentOfType(expr, GrClosableBlock.class, PsiClass.class); - if (expr.getManager().areElementsEquivalent(firstContainingClass, resolved)) { - builder.append(expr.getReferenceName()); - } - else { - builder.append(((PsiClass)resolved).getQualifiedName()).append(".").append(expr.getReferenceName()); - } + builder.append(((PsiClass)resolved).getQualifiedName()).append(".").append(expr.getReferenceName()); } @Override @@ -561,8 +664,8 @@ public class ExpressionGenerator extends Generator { } final GroovyResolveResult candidate = PsiImplUtil.getIndexPropertyMethodCandidate(thisType, argTypes, expression); - GenerationUtil.invokeMethodByResolveResult( - selectedExpression, candidate, "getAt", exprArgs, namedArgs, GrClosableBlock.EMPTY_ARRAY, this,expression + invokeMethodByResolveResult( + selectedExpression, candidate, "getAt", exprArgs, namedArgs, GrClosableBlock.EMPTY_ARRAY, this, expression ); } @@ -574,14 +677,13 @@ public class ExpressionGenerator extends Generator { PsiSubstitutor substitutor, GroovyPsiElement context) { if (method instanceof GrGdkMethod && !method.hasModifierProperty(GrModifier.STATIC)) { - LOG.assertTrue(caller != null); - final GrExpression listOrMap = - GroovyRefactoringUtil.generateArgFromMultiArg(PsiSubstitutor.EMPTY, Arrays.asList(namedArgs), null, method.getProject()); - GrExpression[] newArgs = new GrExpression[exprs.length + 2]; - System.arraycopy(exprs, 0, newArgs, 2, exprs.length); + if (caller == null) { + caller = factory.createExpressionFromText("this", context); + } + GrExpression[] newArgs = new GrExpression[exprs.length + 1]; + System.arraycopy(exprs, 0, newArgs, 1, exprs.length); newArgs[0] = caller; - newArgs[1] = listOrMap; - invokeMethodOn(((GrGdkMethod)method).getStaticMethod(), null, newArgs, GrNamedArgument.EMPTY_ARRAY, closures, substitutor, context); + invokeMethodOn(((GrGdkMethod)method).getStaticMethod(), null, newArgs, namedArgs, closures, substitutor, context); return; } @@ -593,9 +695,11 @@ public class ExpressionGenerator extends Generator { } } else { - LOG.assertTrue(caller != null, "instance method call should have caller"); - caller.accept(this); - builder.append("."); + //LOG.assertTrue(caller != null, "instance method call should have caller"); + if (caller != null) { + caller.accept(this); + builder.append("."); + } } builder.append(method.getName()); final GrClosureSignature signature = GrClosureSignatureUtil.createSignature(method, substitutor); @@ -613,6 +717,7 @@ public class ExpressionGenerator extends Generator { String varName = generateListOrMapVariableDeclaration(listOrMap, type); generateListOrMapElementInsertions(listOrMap, varName); + builder.append(varName); } private void generateListOrMapElementInsertions(GrListOrMap listOrMap, String varName) { @@ -647,16 +752,27 @@ public class ExpressionGenerator extends Generator { context.myStatements.add(insertion.toString()); } } + else { + for (GrExpression arg : listOrMap.getInitializers()) { + StringBuilder insertion = new StringBuilder(); + insertion.append(varName).append(".add("); + arg.accept(new ExpressionGenerator(insertion, context)); + + insertion.append(");"); + context.myStatements.add(insertion.toString()); + } + + } //todo for list } private String generateListOrMapVariableDeclaration(GrListOrMap listOrMap, PsiType type) { StringBuilder declaration = new StringBuilder(); - GenerationUtil.writeType(declaration, type); - final String varName = GenerationUtil.suggestVarName(type, listOrMap, this.context); + writeType(declaration, type); + final String varName = suggestVarName(type, listOrMap, this.context); declaration.append(" ").append(varName).append(" = new "); - GenerationUtil.writeType(declaration, type); + writeType(declaration, type); declaration.append("("); //insert count of elements in list or map diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/GenerationSettings.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/GenerationSettings.java new file mode 100644 index 000000000000..a9ea1a4e43a3 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/GenerationSettings.java @@ -0,0 +1,23 @@ +/* + * 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.refactoring.convertToJava; + +/** + * @author Maxim.Medvedev + */ +public class GenerationSettings { + public static boolean dontReplaceOperatorsWithMethodsForNumbers = true; +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/GenerationUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/GenerationUtil.java index 3cca78c1bb92..237b6c058524 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/GenerationUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/GenerationUtil.java @@ -20,7 +20,8 @@ import com.intellij.psi.*; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; -import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifierList; +import org.jetbrains.plugins.groovy.lang.psi.api.formatter.GrControlStatement; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; @@ -41,14 +42,14 @@ import java.util.List; public class GenerationUtil { private static final Logger LOG = Logger.getInstance("#org.jetbrains.plugins.groovy.refactoring.convertToJava.GenerationUtil"); public static final String[] JAVA_MODIFIERS = new String[]{ - PsiModifier.PUBLIC, - PsiModifier.PROTECTED, - PsiModifier.PRIVATE, - PsiModifier.PACKAGE_LOCAL, - PsiModifier.STATIC, - PsiModifier.ABSTRACT, - PsiModifier.FINAL, - PsiModifier.NATIVE, + PsiModifier.PUBLIC, + PsiModifier.PROTECTED, + PsiModifier.PRIVATE, + PsiModifier.PACKAGE_LOCAL, + PsiModifier.STATIC, + PsiModifier.ABSTRACT, + PsiModifier.FINAL, + PsiModifier.NATIVE, }; private GenerationUtil() { @@ -69,6 +70,16 @@ public class GenerationUtil { builder.replace(builder.length() - 2, builder.length(), ">"); } + static String suggestVarName(GrExpression expr, ExpressionContext expressionContext) { + final DefaultGroovyVariableNameValidator nameValidator = + new DefaultGroovyVariableNameValidator(expr, expressionContext.myUsedVarNames, true); + final String[] varNames = GroovyNameSuggestionUtil.suggestVariableNames(expr, nameValidator); + + LOG.assertTrue(varNames.length > 0); + expressionContext.myUsedVarNames.add(varNames[0]); + return varNames[0]; + } + static String suggestVarName(PsiType type, GroovyPsiElement context, ExpressionContext expressionContext) { final DefaultGroovyVariableNameValidator nameValidator = new DefaultGroovyVariableNameValidator(context, expressionContext.myUsedVarNames, true); @@ -79,9 +90,25 @@ public class GenerationUtil { return varNames[0]; } + public static String validateName(String name, GroovyPsiElement context, ExpressionContext expressionContext) { + return new DefaultGroovyVariableNameValidator(context, expressionContext.myUsedVarNames, true).validateName(name, true); + } + public static void writeCodeReferenceElement(StringBuilder builder, GrCodeReferenceElement referenceElement) { - //todo - throw new UnsupportedOperationException(); + final GroovyResolveResult resolveResult = referenceElement.advancedResolve(); + final PsiElement resolved = resolveResult.getElement(); + if (resolved == null) { + builder.append(referenceElement.getText()); + return; + } + LOG.assertTrue(resolved instanceof PsiClass || resolved instanceof PsiPackage); + if (resolved instanceof PsiClass) { + builder.append(((PsiClass)resolved).getQualifiedName()); + } + else { + builder.append(((PsiPackage)resolved).getQualifiedName()); + } + writeTypeParameters(builder, referenceElement.getTypeArguments()); } public static void invokeMethodByName(GrExpression caller, @@ -146,9 +173,9 @@ public class GenerationUtil { } public static void writeClassModifiers(StringBuilder text, - @Nullable PsiModifierList modifierList, - boolean isInterface, - boolean toplevel) { + @Nullable PsiModifierList modifierList, + boolean isInterface, + boolean toplevel) { if (modifierList == null) { text.append("public "); return; @@ -166,4 +193,45 @@ public class GenerationUtil { writeModifiers(text, modifierList, allowedModifiers.toArray(new String[allowedModifiers.size()])); } + + static void writeStatement(final StringBuilder codeBlockBuilder, + StringBuilder statementBuilder, + @Nullable GrStatement statement, + @Nullable ExpressionContext context) { + final PsiElement parent = statement == null ? null : statement.getParent(); + + final boolean addParentheses; + if (statement == null) { + addParentheses = context != null && context.shouldInsertCurlyBrackets(); + } + else { + addParentheses = + context != null && (context.shouldInsertCurlyBrackets() || context.myStatements.size() > 0) && parent instanceof GrControlStatement; + } + + if (addParentheses) { + codeBlockBuilder.append("{\n"); + } + + if (context != null) { + insertStatementFromContextBefore(codeBlockBuilder, context); + } + codeBlockBuilder.append(statementBuilder); + if (addParentheses) { + codeBlockBuilder.append("}\n"); + } + } + + public static void insertStatementFromContextBefore(StringBuilder codeBlockBuilder, ExpressionContext context) { + for (String st : context.myStatements) { + codeBlockBuilder.append(st).append("\n"); + } + } + + public static void writeStatement(final StringBuilder builder, ExpressionContext context, @Nullable GrStatement statement, StatementWriter writer) { + StringBuilder statementBuilder = new StringBuilder(); + ExpressionContext statementContext = context.copy(); + writer.writeStatement(statementBuilder, statementContext); + writeStatement(builder, statementBuilder, statement, statementContext); + } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/Generator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/Generator.java index 14ece08f12fd..4c9c1e3ea07a 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/Generator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/Generator.java @@ -15,12 +15,12 @@ */ package org.jetbrains.plugins.groovy.refactoring.convertToJava; -import org.jetbrains.plugins.groovy.lang.psi.GroovyRecursiveElementVisitor; +import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor; /** * @author Maxim.Medvedev */ -public abstract class Generator extends GroovyRecursiveElementVisitor { +public abstract class Generator extends GroovyElementVisitor { public abstract StringBuilder getBuilder(); public abstract ExpressionContext getContext(); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/StatementWriter.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/StatementWriter.java new file mode 100644 index 000000000000..b9a28fb426f9 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/StatementWriter.java @@ -0,0 +1,23 @@ +/* + * 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.refactoring.convertToJava; + +/** + * @author Maxim.Medvedev + */ +public interface StatementWriter { + void writeStatement(StringBuilder builder, ExpressionContext context); +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/SwitchStatementGenerator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/SwitchStatementGenerator.java new file mode 100644 index 000000000000..0a0f3087e4b8 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/SwitchStatementGenerator.java @@ -0,0 +1,195 @@ +/* + * 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.refactoring.convertToJava; + +import com.intellij.codeInsight.daemon.impl.analysis.HighlightUtil; +import com.intellij.psi.PsiType; +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.api.statements.GrSwitchStatement; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrBreakStatement; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.clauses.GrCaseSection; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; +import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; +import org.jetbrains.plugins.groovy.lang.psi.util.GroovyConstantExpressionEvaluator; + +/** + * @author Maxim.Medvedev + */ +public class SwitchStatementGenerator { + + private static final boolean LANGUAGE_LEVEL_7_OR_HIGHER = false; + + private SwitchStatementGenerator() { + } + + public static void generate(StringBuilder builder, ExpressionContext context, GrSwitchStatement switchStatement) { + final GrExpression condition = switchStatement.getCondition(); + final GrCaseSection[] caseSections = switchStatement.getCaseSections(); + + final PsiType type = condition == null ? null : TypesUtil.unboxPrimitiveTypeWrapper(condition.getType()); + if (type == null || HighlightUtil.isValidTypeForSwitchSelector(type, LANGUAGE_LEVEL_7_OR_HIGHER)) { + generateSwitch(builder, context, condition, caseSections); + } + else { + generateIfs(builder, context, condition, caseSections); + } + } + + private static void generateIfs(StringBuilder builder, ExpressionContext context, GrExpression condition, GrCaseSection[] caseSections) { + if (caseSections.length == 1 && caseSections[0].getCaseLabel().isDefault()) { + //todo + } + + final GrExpression ref; + if (condition instanceof GrReferenceExpression) { + ref = condition; + } + else { + final String varName = generateConditionVar(builder, context, condition); + ref = GroovyPsiElementFactory.getInstance(context.project).createExpressionFromText(varName); + } + final GrExpression[] args = {ref}; + generateIfFromCaseSection(builder, context, caseSections, 0, args); + } + + private static void generateIfFromCaseSection(StringBuilder builder, + ExpressionContext context, + final GrCaseSection[] caseSections, + final int i, + final GrExpression[] args) { + + GenerationUtil.writeStatement(builder, context, null, new StatementWriter() { + @Override + public void writeStatement(StringBuilder builder, ExpressionContext context) { + GrCaseSection section = caseSections[i]; + boolean isCase = !section.getCaseLabel().isDefault(); + + if (isCase) { + builder.append("if ("); + GenerationUtil.invokeMethodByName( + section.getCaseLabel().getValue(), + "isCase", + args, + GrNamedArgument.EMPTY_ARRAY, + GrClosableBlock.EMPTY_ARRAY, + new ExpressionGenerator(builder, context), + section + ); + builder.append(") {\n"); + } + final ExpressionContext extended = context.extend(); + CodeBlockGenerator generator = new CodeBlockGenerator(builder, extended); + + Outer: + for (int j = i; j < caseSections.length; j++) { + section = caseSections[j]; + final GrStatement[] statements = section.getStatements(); + for (GrStatement statement : statements) { + if (statement instanceof GrBreakStatement && ((GrBreakStatement)statement).getLabelIdentifier() == null) { + break Outer; + } + statement.accept(generator); + builder.append("\n"); + } + } + + if (isCase && i + 1 < caseSections.length) { + builder.append("}\nelse "); + StringBuilder elseBuilder = new StringBuilder(); + final ExpressionContext elseContext = context.extend(); + + generateIfFromCaseSection(elseBuilder, elseContext, caseSections, i + 1, args); + GenerationUtil.insertStatementFromContextBefore(builder, elseContext); + builder.append(elseBuilder); + } + if (context.myStatements.size() > 0) context.setInsertCurlyBrackets(); + } + }); + } + + private static String generateConditionVar(StringBuilder builder, + ExpressionContext context, + GrExpression condition) { + StringBuilder conditionBuilder = new StringBuilder(); + final PsiType type = condition.getType(); + final String varName = GenerationUtil.validateName("switchArg", condition, context); + conditionBuilder.append("final "); + GenerationUtil.writeType(conditionBuilder, type); + conditionBuilder.append(" ").append(varName).append(" = "); + condition.accept(new ExpressionGenerator(conditionBuilder, context)); + conditionBuilder.append(";\n"); + GenerationUtil.insertStatementFromContextBefore(builder, context); + builder.append(conditionBuilder); + return varName; + } + + private static void generateSwitch(StringBuilder builder, + ExpressionContext context, + GrExpression condition, + GrCaseSection[] caseSections) { + builder.append("switch ("); + if (condition != null) { + condition.accept(new ExpressionGenerator(builder, context)); + } + builder.append(") {\n"); + + final ExpressionContext innerContext = context.extend(); + for (GrCaseSection section : caseSections) { + generateCaseSection(builder, context, innerContext, section); + } + + builder.append("}"); + } + + private static void generateCaseSection(StringBuilder builder, + ExpressionContext context, + ExpressionContext innerContext, + GrCaseSection section) { + if (section.getCaseLabel().isDefault()) { + builder.append("default"); + } + else { + builder.append("case "); + final GrExpression value = section.getCaseLabel().getValue(); + Object evaluated; + try { + evaluated = GroovyConstantExpressionEvaluator.evaluate(value); + } + catch (Throwable e) { + evaluated = null; + } + + if (evaluated != null) { + builder.append(evaluated); + } + else if (value != null) { + value.accept(new ExpressionGenerator(builder, context)); + } + } + + builder.append(":\n"); + final GrStatement[] statements = section.getStatements(); + CodeBlockGenerator generator = new CodeBlockGenerator(builder, innerContext); + for (GrStatement statement : statements) { + statement.accept(generator); + builder.append("\n"); + } + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extractMethod/GroovyExtractMethodHandler.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extractMethod/GroovyExtractMethodHandler.java index 298eb237c02e..28bf846f49a2 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extractMethod/GroovyExtractMethodHandler.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extractMethod/GroovyExtractMethodHandler.java @@ -34,13 +34,16 @@ import com.intellij.refactoring.HelpID; import com.intellij.refactoring.RefactoringActionHandler; import com.intellij.refactoring.RefactoringBundle; import com.intellij.refactoring.util.CommonRefactoringUtil; +import com.intellij.util.ArrayUtil; import com.intellij.util.IncorrectOperationException; import com.intellij.util.containers.HashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils; import org.jetbrains.plugins.groovy.lang.psi.GrControlFlowOwner; +import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrMemberOwner; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; @@ -181,7 +184,8 @@ public class GroovyExtractMethodHandler implements RefactoringActionHandler { List returnStatementsCopy = new ArrayList(returnStatements.size()); returnStatementsCopy.addAll(returnStatements); boolean isReturnStatement = ExtractMethodUtil.isReturnStatement(statements[statements.length - 1], returnStatementsCopy); - if (!isReturnStatement && hasReturns || hasInterruptingStatements) { + boolean isLastStatementOfMethod = isLastStatementOfMethodOrClosure(statements); + if (hasReturns && !isLastStatementOfMethod && !isReturnStatement || hasInterruptingStatements) { String message = GroovyRefactoringBundle.message("refactoring.is.not.supported.when.return.statement.interrupts.the.execution.flow"); showErrorMessage(message, project, editor); return false; @@ -210,6 +214,21 @@ public class GroovyExtractMethodHandler implements RefactoringActionHandler { return true; } + private static boolean isLastStatementOfMethodOrClosure(GrStatement[] statements) { + final GrStatement statement0 = statements[0]; + + PsiElement returnFrom = PsiTreeUtil.getParentOfType(statement0, GrMethod.class, GrClosableBlock.class, GroovyFile.class); + if (returnFrom instanceof GrMethod) { + returnFrom = ((GrMethod)returnFrom).getBlock(); + } + LOG.assertTrue(returnFrom instanceof GrStatementOwner); + + final GrStatement[] blockStatements = ((GrStatementOwner)returnFrom).getStatements(); + final GrStatement lastFromBlock = ArrayUtil.getLastElement(blockStatements); + final GrStatement lastStatement = ArrayUtil.getLastElement(statements); + return statement0.getManager().areElementsEquivalent(lastFromBlock, lastStatement); + } + private void runRefactoring(final String methodName, @NotNull final ExtractMethodInfoHelper helper, @NotNull final GrMemberOwner owner, diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/move/MoveGroovyMemberHandler.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/move/MoveGroovyMemberHandler.java index 3e7b7da2d96f..6c6e0232fa27 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/move/MoveGroovyMemberHandler.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/move/MoveGroovyMemberHandler.java @@ -20,17 +20,16 @@ import com.intellij.lang.ASTNode; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.psi.*; -import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtilBase; -import com.intellij.refactoring.move.moveMembers.MoveMemberHandler; +import com.intellij.refactoring.move.moveMembers.MoveJavaMemberHandler; import com.intellij.refactoring.move.moveMembers.MoveMembersOptions; import com.intellij.refactoring.move.moveMembers.MoveMembersProcessor; import com.intellij.refactoring.util.EnumConstantsUtil; -import com.intellij.refactoring.util.RefactoringHierarchyUtil; import com.intellij.util.IncorrectOperationException; import com.intellij.util.VisibilityUtil; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes; +import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory; import org.jetbrains.plugins.groovy.lang.psi.GroovyRecursiveElementVisitor; @@ -48,55 +47,19 @@ import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatem import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; import org.jetbrains.plugins.groovy.refactoring.GroovyChangeContextUtil; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; /** * @author Maxim.Medvedev */ -public class MoveGroovyMemberHandler implements MoveMemberHandler { - public MoveMembersProcessor.MoveMembersUsageInfo getUsage(PsiMember member, - PsiReference psiReference, - Set membersToMove, - PsiClass targetClass) { - PsiElement ref = psiReference.getElement(); - if (ref instanceof GrReferenceExpression) { - GrReferenceExpression refExpr = (GrReferenceExpression)ref; - GrExpression qualifier = refExpr.getQualifierExpression(); - if (RefactoringHierarchyUtil.willBeInTargetClass(refExpr, membersToMove, targetClass, true)) { - // both member and the reference to it will be in target class - if (!isInMovedElement(refExpr, membersToMove)) { - if (qualifier != null) { - return new MoveMembersProcessor.MoveMembersUsageInfo(member, refExpr, null, qualifier, psiReference); // remove qualifier - } - } - else { - if (qualifier instanceof GrReferenceExpression && ((GrReferenceExpression)qualifier).isReferenceTo(member.getContainingClass())) { - return new MoveMembersProcessor.MoveMembersUsageInfo(member, refExpr, null, qualifier, psiReference); // change qualifier - } - } - } - else { - // member in target class, the reference will be outside target class - if (qualifier == null) { - return new MoveMembersProcessor.MoveMembersUsageInfo(member, refExpr, targetClass, refExpr, psiReference); // add qualifier - } - else { - return new MoveMembersProcessor.MoveMembersUsageInfo(member, refExpr, targetClass, qualifier, psiReference); // change qualifier - } - } - } - return null; - } - - private static boolean isInMovedElement(PsiElement element, Set membersToMove) { - for (PsiMember member : membersToMove) { - if (PsiTreeUtil.isAncestor(member, element, false)) return true; - } - return false; - } - - public boolean changeExternalUsage(MoveMembersOptions options, MoveMembersProcessor.MoveMembersUsageInfo usage) { - if (!usage.getElement().isValid()) return true; +public class MoveGroovyMemberHandler extends MoveJavaMemberHandler { + @Override + public boolean changeExternalUsage(@NotNull MoveMembersOptions options, @NotNull MoveMembersProcessor.MoveMembersUsageInfo usage) { + final PsiElement element = usage.getElement(); + if (element == null || !element.isValid()) return true; if (usage.reference instanceof GrReferenceExpression) { GrReferenceExpression refExpr = (GrReferenceExpression)usage.reference; @@ -119,14 +82,14 @@ public class MoveGroovyMemberHandler implements MoveMemberHandler { return false; } - public PsiMember doMove(MoveMembersOptions options, PsiMember member, PsiElement anchor, PsiClass targetClass) { - - PsiMember memberCopy; - + @Override + @NotNull + public PsiMember doMove(@NotNull MoveMembersOptions options, @NotNull PsiMember member, PsiElement anchor, @NotNull PsiClass targetClass) { GroovyChangeContextUtil.encodeContextInfo(member); + PsiMember memberCopy; if (options.makeEnumConstant() && - member instanceof PsiVariable && + member instanceof GrVariable && EnumConstantsUtil.isSuitableForEnumConstant(((PsiVariable)member).getType(), targetClass)) { memberCopy = createEnumConstant(member.getName(), ((GrVariable)member).getInitializerGroovy(), member.getProject()); member.delete(); @@ -186,7 +149,8 @@ public class MoveGroovyMemberHandler implements MoveMemberHandler { return memberCopy; } - public void decodeContextInfo(PsiElement scope) { + @Override + public void decodeContextInfo(@NotNull PsiElement scope) { GroovyChangeContextUtil.decodeContextInfo(scope, null, null); } @@ -222,7 +186,7 @@ public class MoveGroovyMemberHandler implements MoveMemberHandler { return false; } - public static boolean hasOnDemandStaticImport(final PsiElement element, final PsiClass aClass) { + private static boolean hasOnDemandStaticImport(final PsiElement element, final PsiClass aClass) { if (element.getContainingFile() instanceof GroovyFile) { final GrImportStatement[] importStatements = ((GroovyFile)element.getContainingFile()).getImportStatements(); for (GrImportStatement stmt : importStatements) { @@ -235,8 +199,9 @@ public class MoveGroovyMemberHandler implements MoveMemberHandler { return false; } + @Override @Nullable - public PsiElement getAnchor(final PsiMember member, final PsiClass targetClass) { + public PsiElement getAnchor(@NotNull final PsiMember member, @NotNull final PsiClass targetClass) { if (member instanceof GrField && member.hasModifierProperty(PsiModifier.STATIC)) { final List referencedFields = new ArrayList(); final GrExpression psiExpression = ((GrField)member).getInitializerGroovy(); @@ -274,13 +239,13 @@ public class MoveGroovyMemberHandler implements MoveMemberHandler { return elementFactory.createEnumConstantFromText(enumConstantText); } - private static PsiElement addEnumConstant(PsiClass targetClass, GrEnumConstant constant, PsiElement anchor) { + private static PsiElement addEnumConstant(PsiClass targetClass, GrEnumConstant constant, @Nullable PsiElement anchor) { if (targetClass instanceof GrEnumTypeDefinition) { final GrEnumTypeDefinition enumeration = (GrEnumTypeDefinition)targetClass; final GrEnumConstantList constantList = enumeration.getEnumConstantList(); if (constantList != null) { ASTNode node = constantList.getNode(); - node.addLeaf(GroovyElementTypes.mCOMMA, ",", node.getFirstChildNode()); + node.addLeaf(GroovyTokenTypes.mCOMMA, ",", node.getFirstChildNode()); return constantList.addBefore(constant, constantList.getFirstChild()); } else { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/util/dynamicMembers/DynamicMemberUtils.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/util/dynamicMembers/DynamicMemberUtils.java index 7548e3cc7e2b..1ccfd03583a8 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/util/dynamicMembers/DynamicMemberUtils.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/util/dynamicMembers/DynamicMemberUtils.java @@ -244,8 +244,6 @@ public class DynamicMemberUtils { private static class GrDynamicMethodWithCache extends GrDynamicMethodImpl implements DynamicElement { - private PsiType myInferredReturnType; - private PsiType myReturnType; private PsiTypeParameter[] myTypeParameters; private GrParameterList myParameterList; private String[] namedParameters; @@ -254,8 +252,6 @@ public class DynamicMemberUtils { public GrDynamicMethodWithCache(GrMethod method, String source) { super(method); - myInferredReturnType = super.getInferredReturnType(); - myReturnType = super.getReturnType(); myTypeParameters = super.getTypeParameters(); myParameterList = super.getParameterList(); namedParameters = super.getNamedParametersArray(); @@ -267,16 +263,6 @@ public class DynamicMemberUtils { return myMethod.getText(); } - @Override - public PsiType getInferredReturnType() { - return myInferredReturnType; - } - - @Override - public PsiType getReturnType() { - return myReturnType; - } - @NotNull @Override public PsiTypeParameter[] getTypeParameters() { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyAutoPopupTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyAutoPopupTest.groovy index b533e24f6cda..e45f0617ccbe 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyAutoPopupTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyAutoPopupTest.groovy @@ -95,4 +95,10 @@ class GroovyAutoPopupTest extends CompletionAutoPopupTestCase { assert myFixture.lookupElementStrings == [ArrayIndexOutOfBoundsException.simpleName] } + public void testNoWordCompletionAutoPopup() { + myFixture.configureByText "a.groovy", 'def foo = "f"' + type 'o' + assert !lookup + } + } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy index ef233c91590e..755f174daee9 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy @@ -604,13 +604,6 @@ def foo(def a) {2} return foo()""" } - void checkCompletion(String before, String type, String after) { - myFixture.configureByText("a.groovy", before) - myFixture.completeBasic() - myFixture.type(type) - myFixture.checkResult(after) - } - public void testFinishClassNameWithSquareBracket() { myFixture.addClass("class AbcdClass {}; class AbcdeClass {}") checkCompletion("Abcd", '[', "AbcdClass[]") @@ -674,6 +667,9 @@ a.""") return completion.find {println it.lookupString;itemToCheck == it.lookupString} } + public void testWordCompletionInLiterals() { + checkSingleItemCompletion('def foo = "fo"', 'def foo = "foo"') + } public void testShowAccessor() { assertNotNull doContainsTest("getFoo", """ @@ -685,4 +681,13 @@ def a = new MyClass() a.g """) } + + public void testContinue() { + assertNotNull doContainsTest("continue", """ +def conti = 4 +while(true) { + if (tst) cont +}""") + + } } \ No newline at end of file diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTestBase.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTestBase.java index b1395b7ef8f0..8ceaaa150941 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTestBase.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTestBase.java @@ -48,4 +48,18 @@ abstract public class GroovyCompletionTestBase extends LightCodeInsightFixtureTe assertNotNull(list); UsefulTestCase.assertOrderedEquals(list, variants); } + + public void checkCompletion(String before, String type, String after) { + myFixture.configureByText("a.groovy", before); + myFixture.completeBasic(); + myFixture.type(type); + myFixture.checkResult(after); + } + + public void checkSingleItemCompletion(String before, String after) { + myFixture.configureByText("a.groovy", before); + myFixture.completeBasic(); + myFixture.checkResult(after); + } + } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.java index e2a9829b3395..0bbd077d5d68 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.java @@ -366,4 +366,8 @@ public class GroovyHighlightingTest extends LightCodeInsightFixtureTestCase { public void testAnonymousClassArgList() { doTest(new GroovyAssignabilityCheckInspection()); } + + public void testConstructorWithAllParametersOptional() { + doTest(); + } } \ No newline at end of file diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyMapAttributeTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyMapAttributeTest.groovy index 4419d7e2d5d8..5504d04a1c1d 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyMapAttributeTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyMapAttributeTest.groovy @@ -434,7 +434,7 @@ class CccList extends Ccc {} println(new CccMap(foo: [:])) println(new CccList(foo: [])) -println(new CccMap(foo: [])) +println(new CccMap(foo: [])) println(new CccList(foo: [:])) """ } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveMethodTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveMethodTest.groovy index 7ed7a1038c4e..ca9937dc803d 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveMethodTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveMethodTest.groovy @@ -648,4 +648,10 @@ class Zoo { public void resoleAsType() { assertInstanceOf resolve("A.groovy"), GrMethod } + + public void testPlusAssignment() { + final PsiElement resolved = resolve("A.groovy") + assertInstanceOf resolved, GrMethod + assertEquals("plus", resolved.name) + } } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolvePropertyTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolvePropertyTest.groovy index 44146920115f..956083d4745a 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolvePropertyTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolvePropertyTest.groovy @@ -654,7 +654,15 @@ setFoo(2) assertInstanceOf resolved, GrParameter } - public void dontResolveForVarOutsideOfFor(){ + public void testDontResolveForVarOutsideOfFor(){ assertNull resolve("A.groovy") } + + public void testOperatorOverloading() { + assertInstanceOf resolve("A.groovy"), GrAccessorMethod + } + + public void testResolveClosureOverloader() { + assertInstanceOf resolve("A.groovy"), GrAccessorMethod + } } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInferenceTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInferenceTest.java index ac8e9b5c568f..c7fbb0dbb7ce 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInferenceTest.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInferenceTest.java @@ -171,7 +171,7 @@ public class TypeInferenceTest extends GroovyResolveTestCase { } public void testTupleWithNullInIt() { - assertTypeEquals("java.util.List", "A.groovy"); + assertTypeEquals("java.util.ArrayList", "A.groovy"); } public void testImplicitlyReturnedMethodCall() { @@ -181,4 +181,27 @@ public class TypeInferenceTest extends GroovyResolveTestCase { public void testInferWithClosureType() { assertTypeEquals("java.util.Date", "A.groovy"); } + + public void testPlusEquals1() { + assertTypeEquals("Test", "A.groovy"); + } + + public void testPlusEquals2() { + assertTypeEquals("java.lang.String", "A.groovy"); + } + + public void testPlusEquals3() { + assertTypeEquals("java.lang.String", "A.groovy"); + } + public void testPlusEqualsClosure() { + assertTypeEquals("java.lang.String", "A.groovy"); + } + + public void testGetAtClosure() { + assertTypeEquals("java.lang.String", "A.groovy"); + } + + public void testPreferMethodOverloader() { + assertTypeEquals("java.lang.String", "A.groovy"); + } } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/convertToJava/CodeBlockGenerationTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/convertToJava/CodeBlockGenerationTest.groovy new file mode 100644 index 000000000000..669155ccc9ed --- /dev/null +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/convertToJava/CodeBlockGenerationTest.groovy @@ -0,0 +1,107 @@ +/* + * 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.refactoring.convertToJava; + + +import com.intellij.lang.StdLanguages +import com.intellij.openapi.module.Module +import com.intellij.openapi.roots.ContentEntry +import com.intellij.openapi.roots.ModifiableRootModel +import com.intellij.openapi.roots.OrderRootType +import com.intellij.openapi.roots.libraries.Library +import com.intellij.openapi.vfs.JarFileSystem +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.psi.PsiFile +import com.intellij.psi.impl.source.PostprocessReformattingAspect +import com.intellij.testFramework.LightProjectDescriptor +import com.intellij.testFramework.fixtures.DefaultLightProjectDescriptor +import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase +import org.jetbrains.annotations.NotNull +import org.jetbrains.plugins.groovy.lang.psi.GroovyFile +import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.GrTopStatement +import org.jetbrains.plugins.groovy.util.TestUtils + +/** + * @author Maxim.Medvedev + */ +public class CodeBlockGenerationTest extends LightCodeInsightFixtureTestCase { + public static final DefaultLightProjectDescriptor GROOVY_17_PROJECT_DESCRIPTOR = new DefaultLightProjectDescriptor() { + @Override + public void configureModule(Module module, ModifiableRootModel model, ContentEntry contentEntry) { + final Library.ModifiableModel modifiableModel = model.moduleLibraryTable.createLibrary("GROOVY").modifiableModel; + final VirtualFile groovyJar = JarFileSystem.instance.refreshAndFindFileByPath(TestUtils.mockGroovy1_7LibraryName + "!/"); + modifiableModel.addRoot(groovyJar, OrderRootType.CLASSES); + modifiableModel.commit(); + } + }; + + @NotNull + @Override + protected LightProjectDescriptor getProjectDescriptor() { + return GROOVY_17_PROJECT_DESCRIPTOR; + } + + @Override + protected String getBasePath() { + return TestUtils.testDataPath + "refactoring/convertGroovyToJava/codeBlock"; + } + + private void doTest() { + final String testName = getTestName(false) + final PsiFile file = myFixture.configureByFile(testName + ".groovy"); + assertInstanceOf file, GroovyFile + + GrTopStatement[] statements = file.topStatements + final StringBuilder builder = new StringBuilder() + def generator = new CodeBlockGenerator(builder, new ExpressionContext(project)); + for (def statement: statements) { + statement.accept(generator); + builder.append("\n") + } + + final PsiFile result = createLightFile(testName + ".java", StdLanguages.JAVA, builder.toString()) + PostprocessReformattingAspect.getInstance(project).doPostponedFormatting() + final String text = result.text + final String expected = psiManager.findFile(myFixture.copyFileToProject(testName + ".java")).text + assertEquals expected, text + } + + void testSwitch1() {doTest()} + void testSwitch2() {doTest()} + void testSwitch3() {doTest()} + void testSwitch4() {doTest()} + + void _testWhile1() {doTest()} + void _testWhile2() {doTest()} + void _testWhile3() {doTest()} + + void testRefExpr() { + myFixture.addFileToProject "Bar.groovy", """ +class Bar { + def foo = 2 + + def getBar() {3} +} +class MyCat { + static getAbc(Bar b) { + return 4 + } +} +""" + + doTest() + } +} diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/convertToJava/ExpressionGenerationTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/convertToJava/ExpressionGenerationTest.groovy new file mode 100644 index 000000000000..f82d6cd060b6 --- /dev/null +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/convertToJava/ExpressionGenerationTest.groovy @@ -0,0 +1,79 @@ +/* + * 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.refactoring.convertToJava + +import com.intellij.lang.StdLanguages +import com.intellij.openapi.module.Module +import com.intellij.openapi.roots.ContentEntry +import com.intellij.openapi.roots.ModifiableRootModel +import com.intellij.openapi.roots.OrderRootType +import com.intellij.openapi.roots.libraries.Library +import com.intellij.openapi.vfs.JarFileSystem +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.psi.PsiFile +import com.intellij.psi.impl.source.PostprocessReformattingAspect +import com.intellij.testFramework.LightProjectDescriptor +import com.intellij.testFramework.fixtures.DefaultLightProjectDescriptor +import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase +import org.jetbrains.annotations.NotNull +import org.jetbrains.plugins.groovy.lang.psi.GroovyFile +import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.GrTopStatement +import org.jetbrains.plugins.groovy.util.TestUtils + +/** + * @author Maxim.Medvedev + */ +class ExpressionGenerationTest extends LightCodeInsightFixtureTestCase { + public static final DefaultLightProjectDescriptor GROOVY_17_PROJECT_DESCRIPTOR = new DefaultLightProjectDescriptor() { + @Override + public void configureModule(Module module, ModifiableRootModel model, ContentEntry contentEntry) { + final Library.ModifiableModel modifiableModel = model.getModuleLibraryTable().createLibrary("GROOVY").getModifiableModel(); + final VirtualFile groovyJar = JarFileSystem.getInstance().refreshAndFindFileByPath(TestUtils.getMockGroovy1_7LibraryName() + "!/"); + modifiableModel.addRoot(groovyJar, OrderRootType.CLASSES); + modifiableModel.commit(); + } + }; + + @NotNull + @Override + protected LightProjectDescriptor getProjectDescriptor() { + return GROOVY_17_PROJECT_DESCRIPTOR; + } + + @Override + protected String getBasePath() { + return TestUtils.testDataPath + "/refactoring/convertGroovyToJava/codeBlock"; + } + + private void doTest() { + final String testName = getTestName(false); + final PsiFile file = myFixture.configureByFile(testName + ".groovy"); + assertInstanceOf file, GroovyFile + + GrTopStatement[] statements = file.topStatements + final StringBuilder builder = new StringBuilder() + statements.last().accept(new ExpressionGenerator(builder, new ExpressionContext(project))) + + final PsiFile result = createLightFile(testName + ".java", StdLanguages.JAVA, builder.toString()) + PostprocessReformattingAspect.getInstance(project).doPostponedFormatting() + final String text = result.text + final String expected = psiManager.findFile(myFixture.copyFileToProject(testName + ".java")).text + assertEquals expected, text + } + + void testAssignment() {//todo + } +} diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/extractMethod/ExtractMethodTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/extractMethod/ExtractMethodTest.java index 386a7d4063e8..f94cbb390a0d 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/extractMethod/ExtractMethodTest.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/extractMethod/ExtractMethodTest.java @@ -97,4 +97,6 @@ public class ExtractMethodTest extends LightGroovyTestCase { public void testMultiOutput5() {doTest();} public void testDontShortenRefsIncorrect() {doTest();} + + public void testLastBlockStatementInterruptsControlFlow() {doTest();} } \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/refactoring/extractMethod/implicitReturn.test b/plugins/groovy/testdata/groovy/refactoring/extractMethod/implicitReturn.test index 5888230be0f0..0e1d7f2e8f48 100644 --- a/plugins/groovy/testdata/groovy/refactoring/extractMethod/implicitReturn.test +++ b/plugins/groovy/testdata/groovy/refactoring/extractMethod/implicitReturn.test @@ -10,7 +10,7 @@ def List getMethodArguments(def methodCall) { return testMethod(methodCall) } -private List testMethod(methodCall) { +private ArrayList testMethod(methodCall) { def argumentsExpression = methodCall.arguments if (respondsTo(argumentsExpression, 'getExpressions')) { return [1, 2, 3] diff --git a/plugins/groovy/testdata/groovy/refactoring/extractMethod/lastBlockStatementInterruptsControlFlow.test b/plugins/groovy/testdata/groovy/refactoring/extractMethod/lastBlockStatementInterruptsControlFlow.test new file mode 100644 index 000000000000..e6b0b43605fc --- /dev/null +++ b/plugins/groovy/testdata/groovy/refactoring/extractMethod/lastBlockStatementInterruptsControlFlow.test @@ -0,0 +1,15 @@ +def foo() { + if (abc) { + println 'def' + } +} +----- +def foo() { + testMethod() +} + +private def testMethod() { + if (abc) { + println 'def' + } +} \ No newline at end of file diff --git a/plugins/groovy/testdata/highlighting/CallIsNotApplicable.groovy b/plugins/groovy/testdata/highlighting/CallIsNotApplicable.groovy index 915316db3d7f..6b0cbfd391b6 100644 --- a/plugins/groovy/testdata/highlighting/CallIsNotApplicable.groovy +++ b/plugins/groovy/testdata/highlighting/CallIsNotApplicable.groovy @@ -5,5 +5,5 @@ class IntCategory { } use(IntCategory) { - print 2(3, 4) + print 2(3, 4) } \ No newline at end of file diff --git a/plugins/groovy/testdata/highlighting/ConstructorWithAllParametersOptional.groovy b/plugins/groovy/testdata/highlighting/ConstructorWithAllParametersOptional.groovy new file mode 100644 index 000000000000..5e28c6b1c7a5 --- /dev/null +++ b/plugins/groovy/testdata/highlighting/ConstructorWithAllParametersOptional.groovy @@ -0,0 +1,14 @@ +class Base { + def Base(int x = 0, int y=5){} +} + +class Inheritor extends Base{ +} + +class Base2 { + def Base2(int x){} +} + +class Inheritor2 extends Base2 { + +} \ No newline at end of file diff --git a/plugins/groovy/testdata/highlighting/PathCallIsNotApplicable.groovy b/plugins/groovy/testdata/highlighting/PathCallIsNotApplicable.groovy index f5e509f62094..833068eb974b 100644 --- a/plugins/groovy/testdata/highlighting/PathCallIsNotApplicable.groovy +++ b/plugins/groovy/testdata/highlighting/PathCallIsNotApplicable.groovy @@ -1,5 +1,5 @@ class IntCategory { - def call(Integer i, int q) { + static def call(Integer i, int q) { return { String s -> s + q; } @@ -7,5 +7,5 @@ class IntCategory { } use(IntCategory) { - print 2(3)("a", "b") + print 2(3)("a", "b") } \ No newline at end of file diff --git a/plugins/groovy/testdata/highlighting/TupleTypeAssignments.groovy b/plugins/groovy/testdata/highlighting/TupleTypeAssignments.groovy index 3ff59e526b1c..86688399c05c 100644 --- a/plugins/groovy/testdata/highlighting/TupleTypeAssignments.groovy +++ b/plugins/groovy/testdata/highlighting/TupleTypeAssignments.groovy @@ -1,5 +1,5 @@ def foo = [1, 2, 3] -Double d = [1, 2, 3] -List list = ["1", "2"] +Double d = [1, 2, 3] +List list = ["1", "2"] List doubleList = [1, 2] List secondDoubleList = [1.2, 2.5] \ No newline at end of file diff --git a/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/refExpr.groovy b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/refExpr.groovy new file mode 100644 index 000000000000..44f74c60eddf --- /dev/null +++ b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/refExpr.groovy @@ -0,0 +1,10 @@ +print new Bar().foo +print new Bar().bar + +def bar = new Bar() + +print bar?.foo + +def file = new File("") +print file.text + diff --git a/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/refExpr.java b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/refExpr.java new file mode 100644 index 000000000000..15b1127bbadb --- /dev/null +++ b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/refExpr.java @@ -0,0 +1,6 @@ +print(new Bar().getFoo()); +print(new Bar().getBar()); +Bar bar = new Bar(); +print(bar == null ? null : bar.getFoo()); +java.io.File file = new java.io.File(""); +print(org.codehaus.groovy.runtime.DefaultGroovyMethods.getText(file)); diff --git a/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/switch1.groovy b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/switch1.groovy new file mode 100644 index 000000000000..f1227d34d243 --- /dev/null +++ b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/switch1.groovy @@ -0,0 +1,15 @@ +def a = 2 +switch (a) { + case 1: + print a; + case 2: + print a+2 + break + case 3: + print a-1 + break + default: + print "foooo"; +} + +print "wow" diff --git a/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/switch1.java b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/switch1.java new file mode 100644 index 000000000000..41c1f8e9768b --- /dev/null +++ b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/switch1.java @@ -0,0 +1,14 @@ +java.lang.Integer a = 2; +switch (a) { +case 1: +print(a); +case 2: +print(a + 2); +break; +case 3: +print(a - 1); +break; +default: +print("foooo"); +} +print("wow"); diff --git a/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/switch2.groovy b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/switch2.groovy new file mode 100644 index 000000000000..460c787527ed --- /dev/null +++ b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/switch2.groovy @@ -0,0 +1,8 @@ +def a = 2; + +switch (a) { + case 2 + [4, 5]: + print a; + case [1, 2]: + print a; +} diff --git a/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/switch2.java b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/switch2.java new file mode 100644 index 000000000000..b1399d2c654a --- /dev/null +++ b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/switch2.java @@ -0,0 +1,13 @@ +java.lang.Integer a = 2; +java.util.ArrayList integers = new java.util.ArrayList(2); +integers.add(4); +integers.add(5); +java.util.ArrayList integers1 = new java.util.ArrayList(2); +integers1.add(1); +integers1.add(2); +switch (a) { +case 2 + integers: +print(a); +case integers1: +print(a); +} diff --git a/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/switch3.groovy b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/switch3.groovy new file mode 100644 index 000000000000..134f8d552102 --- /dev/null +++ b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/switch3.groovy @@ -0,0 +1,11 @@ +def date = new Date(2011, 04, 09) + +switch (date) { + case new Date(20, 11, 23): + print "aaa" + case new Date(45, 1, 2): + print "bbb" + break + default: + print "ccc" +} diff --git a/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/switch3.java b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/switch3.java new file mode 100644 index 000000000000..b1f9dc5ded69 --- /dev/null +++ b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/switch3.java @@ -0,0 +1,10 @@ +java.util.Date date = new java.util.Date(2011, 4, 9); +if (org.codehaus.groovy.runtime.DefaultGroovyMethods.isCase(new java.util.Date(20, 11, 23), date)) { +print("aaa"); +print("bbb"); +} +else if (org.codehaus.groovy.runtime.DefaultGroovyMethods.isCase(new java.util.Date(45, 1, 2), date)) { +print("bbb"); +} +else print("ccc"); + diff --git a/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/switch4.groovy b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/switch4.groovy new file mode 100644 index 000000000000..6975afb5d3de --- /dev/null +++ b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/switch4.groovy @@ -0,0 +1,11 @@ +def date = new Date(2011, 04, 09) + +switch (date) { + case new Date(20, 11, 23): + print "aaa" + case [1]: + print "bbb" + break + default: + print "ccc" +} diff --git a/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/switch4.java b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/switch4.java new file mode 100644 index 000000000000..60b25a0e977d --- /dev/null +++ b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/switch4.java @@ -0,0 +1,14 @@ +java.util.Date date = new java.util.Date(2011, 4, 9); +if (org.codehaus.groovy.runtime.DefaultGroovyMethods.isCase(new java.util.Date(20, 11, 23), date)) { +print("aaa"); +print("bbb"); +} +else { +java.util.ArrayList integers = new java.util.ArrayList(1); +integers.add(1); +if (org.codehaus.groovy.runtime.DefaultGroovyMethods.isCase(integers, date)) { +print("bbb"); +} +else print("ccc"); +} + diff --git a/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/while1.groovy b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/while1.groovy index be9f67913ed1..d66a8772c33d 100644 --- a/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/while1.groovy +++ b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/while1.groovy @@ -1,2 +1,2 @@ def a = 5; -while (a < 20) a-- +while (a < 20) a=a+2 diff --git a/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/while1.java b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/while1.java index cae661e2816f..095da612376e 100644 --- a/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/while1.java +++ b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/while1.java @@ -1,2 +1,2 @@ int a = 5; -while (a < 20) a--; \ No newline at end of file +while (a < 20) a=a+2; \ No newline at end of file diff --git a/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/while2.groovy b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/while2.groovy index 860ebeac05b3..cab5857e93eb 100644 --- a/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/while2.groovy +++ b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/while2.groovy @@ -1,2 +1,2 @@ def a = 5; -while (![1, 2, 3, 4].find {a > it}) a-- \ No newline at end of file +while (![1, 2, 3, 4].find {a > it}) a=a-1 \ No newline at end of file diff --git a/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/while2.java b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/while2.java index 068c3cc6ae1d..c9ae856cbbbd 100644 --- a/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/while2.java +++ b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/while2.java @@ -8,4 +8,4 @@ while (!org.codehaus.groovy.runtime.DefaultGroovyMethods.find(list, new groovy.l boolean doCall(java.lang.Integer it) { return a.equals(it); } -})) a--; +})) a=a-1; diff --git a/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/while3.groovy b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/while3.groovy new file mode 100644 index 000000000000..2b74fe6c2da4 --- /dev/null +++ b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/while3.groovy @@ -0,0 +1,2 @@ +def list = [1, 2, 3] +while (list -[3, 4]) list-=1 diff --git a/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/while3.java b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/while3.java new file mode 100644 index 000000000000..c0070d5b11b1 --- /dev/null +++ b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/while3.java @@ -0,0 +1,8 @@ +java.util.List list = new java.util.ArrayList(3); +list.add(1); +list.add(2); +list.add(3); +java.util.List list1 = new java.util.ArrayList(2); +list1.add(3); +list1.add(4); +while (!org.codehaus.groovy.runtime.DefaultGroovyMethods.minus(list, list1).isEmpty()) list = org.codehaus.groovy.runtime.DefaultGroovyMethods.minus(list, 1); diff --git a/plugins/groovy/testdata/resolve/inference/getAtClosure/A.groovy b/plugins/groovy/testdata/resolve/inference/getAtClosure/A.groovy new file mode 100644 index 000000000000..65d39113288b --- /dev/null +++ b/plugins/groovy/testdata/resolve/inference/getAtClosure/A.groovy @@ -0,0 +1,10 @@ +class Test { + def getAt = {def a -> + "a" + } +} +def test = new Test() +test = test[2] + +print test + diff --git a/plugins/groovy/testdata/resolve/inference/plusEquals1/A.groovy b/plugins/groovy/testdata/resolve/inference/plusEquals1/A.groovy new file mode 100644 index 000000000000..3e80f23377fb --- /dev/null +++ b/plugins/groovy/testdata/resolve/inference/plusEquals1/A.groovy @@ -0,0 +1,9 @@ +class Test { + def plus(def a) { + "a" + } +} +def test = new Test() +test += 2 +print test + diff --git a/plugins/groovy/testdata/resolve/inference/plusEquals2/A.groovy b/plugins/groovy/testdata/resolve/inference/plusEquals2/A.groovy new file mode 100644 index 000000000000..29757767b091 --- /dev/null +++ b/plugins/groovy/testdata/resolve/inference/plusEquals2/A.groovy @@ -0,0 +1,9 @@ +class Test { + def plus(def a) { + "a" + } +} +def test = new Test() +test += 2 +print test + diff --git a/plugins/groovy/testdata/resolve/inference/plusEquals3/A.groovy b/plugins/groovy/testdata/resolve/inference/plusEquals3/A.groovy new file mode 100644 index 000000000000..699ebddccdef --- /dev/null +++ b/plugins/groovy/testdata/resolve/inference/plusEquals3/A.groovy @@ -0,0 +1,9 @@ +class Test { + def plus(def a) { + "a" + } +} +def test = new Test() +def aa = test += 2 +print test +print aa diff --git a/plugins/groovy/testdata/resolve/inference/plusEqualsClosure/A.groovy b/plugins/groovy/testdata/resolve/inference/plusEqualsClosure/A.groovy new file mode 100644 index 000000000000..4fa132d4ee82 --- /dev/null +++ b/plugins/groovy/testdata/resolve/inference/plusEqualsClosure/A.groovy @@ -0,0 +1,9 @@ +class Test { + def plus = {def a -> + "a" + } +} +def test = new Test() +test += 2 +print test + diff --git a/plugins/groovy/testdata/resolve/inference/preferMethodOverloader/A.groovy b/plugins/groovy/testdata/resolve/inference/preferMethodOverloader/A.groovy new file mode 100644 index 000000000000..eae1ac6af4f9 --- /dev/null +++ b/plugins/groovy/testdata/resolve/inference/preferMethodOverloader/A.groovy @@ -0,0 +1,14 @@ +class Base { + def getAt(def a) { + "2" + } +} +class Test extends Base { + def getAt = {def a -> + 2 + } +} +def test = new Test() +test = test[2] +print test + diff --git a/plugins/groovy/testdata/resolve/method/plusAssignment/A.groovy b/plugins/groovy/testdata/resolve/method/plusAssignment/A.groovy new file mode 100644 index 000000000000..f0a832c95104 --- /dev/null +++ b/plugins/groovy/testdata/resolve/method/plusAssignment/A.groovy @@ -0,0 +1,7 @@ +class Test { + def plus(def a) { + new Test() + } +} +def test=new Test() +test+=2 \ No newline at end of file diff --git a/plugins/groovy/testdata/resolve/property/operatorOverloading/A.groovy b/plugins/groovy/testdata/resolve/property/operatorOverloading/A.groovy new file mode 100644 index 000000000000..cb084c713102 --- /dev/null +++ b/plugins/groovy/testdata/resolve/property/operatorOverloading/A.groovy @@ -0,0 +1,9 @@ +class Test { + def plus = {def a -> + "a" + } +} +def test = new Test() +test += 2 +print test + diff --git a/plugins/groovy/testdata/resolve/property/resolveClosureOverloader/A.groovy b/plugins/groovy/testdata/resolve/property/resolveClosureOverloader/A.groovy new file mode 100644 index 000000000000..0894a449f4d3 --- /dev/null +++ b/plugins/groovy/testdata/resolve/property/resolveClosureOverloader/A.groovy @@ -0,0 +1,24 @@ +class Base { + def getAt(def a) { + 2 + } +} +class Test extends Base { + def plus = {int a -> + "a" + } + + def plus(String a) {2} + + def call = { def a -> + "a" + } + + def call() {2} +} + + +def test = new Test() +print test + 2 + + diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/HgContentRevision.java b/plugins/hg4idea/src/org/zmlx/hg4idea/HgContentRevision.java index 41d1d3dfe930..d213e5703b51 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/HgContentRevision.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/HgContentRevision.java @@ -24,6 +24,7 @@ import org.apache.commons.lang.builder.HashCodeBuilder; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.zmlx.hg4idea.command.HgCatCommand; +import org.zmlx.hg4idea.util.HgUtil; import java.io.UnsupportedEncodingException; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/HgFileRevision.java b/plugins/hg4idea/src/org/zmlx/hg4idea/HgFileRevision.java index 070190b7ae33..240febc364e3 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/HgFileRevision.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/HgFileRevision.java @@ -18,6 +18,7 @@ import com.intellij.openapi.vcs.history.VcsFileRevision; import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; import org.zmlx.hg4idea.command.HgCatCommand; +import org.zmlx.hg4idea.util.HgUtil; import java.io.IOException; import java.io.UnsupportedEncodingException; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/HgPusher.java b/plugins/hg4idea/src/org/zmlx/hg4idea/HgPusher.java index 6d9932321be5..399290077632 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/HgPusher.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/HgPusher.java @@ -25,6 +25,8 @@ import org.zmlx.hg4idea.command.HgPushCommand; import org.zmlx.hg4idea.execution.HgCommandResult; import org.zmlx.hg4idea.execution.HgCommandResultHandler; import org.zmlx.hg4idea.ui.HgPushDialog; +import org.zmlx.hg4idea.util.HgErrorUtil; +import org.zmlx.hg4idea.util.HgUtil; import java.util.List; import java.util.regex.Matcher; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/HgRootsHandler.java b/plugins/hg4idea/src/org/zmlx/hg4idea/HgRootsHandler.java index 5da62435f18a..4aef2c466071 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/HgRootsHandler.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/HgRootsHandler.java @@ -23,6 +23,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.vcsUtil.VcsUtil; import gnu.trove.THashSet; import org.jetbrains.annotations.Nullable; +import org.zmlx.hg4idea.util.HgUtil; import java.util.ArrayList; import java.util.List; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/HgVFSListener.java b/plugins/hg4idea/src/org/zmlx/hg4idea/HgVFSListener.java index 0f98a89c5eca..10c8dbac9970 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/HgVFSListener.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/HgVFSListener.java @@ -27,6 +27,7 @@ import com.intellij.util.ui.VcsBackgroundTask; import com.intellij.vcsUtil.VcsUtil; import org.jetbrains.annotations.NotNull; import org.zmlx.hg4idea.command.*; +import org.zmlx.hg4idea.util.HgUtil; import java.util.*; import java.util.concurrent.atomic.AtomicReference; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/HgVcs.java b/plugins/hg4idea/src/org/zmlx/hg4idea/HgVcs.java index a58acb43336b..0afbaf0ec6b4 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/HgVcs.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/HgVcs.java @@ -59,6 +59,7 @@ import org.zmlx.hg4idea.provider.update.HgIntegrateEnvironment; import org.zmlx.hg4idea.provider.update.HgUpdateEnvironment; import org.zmlx.hg4idea.ui.HgChangesetStatus; import org.zmlx.hg4idea.ui.HgCurrentBranchStatus; +import org.zmlx.hg4idea.util.HgUtil; import javax.swing.*; import java.io.File; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAbstractFilesAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAbstractFilesAction.java index 2efb5e73116a..82e8489074a9 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAbstractFilesAction.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAbstractFilesAction.java @@ -21,7 +21,7 @@ import com.intellij.openapi.vcs.ProjectLevelVcsManager; import com.intellij.openapi.vcs.TransactionRunnable; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vfs.VirtualFile; -import org.zmlx.hg4idea.HgUtil; +import org.zmlx.hg4idea.util.HgUtil; import org.zmlx.hg4idea.HgVcs; import java.lang.reflect.InvocationTargetException; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAbstractGlobalAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAbstractGlobalAction.java index e752629af847..1c4e1ea0c350 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAbstractGlobalAction.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAbstractGlobalAction.java @@ -18,7 +18,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.vcsUtil.VcsUtil; import org.jetbrains.annotations.Nullable; -import org.zmlx.hg4idea.HgUtil; +import org.zmlx.hg4idea.util.HgUtil; import org.zmlx.hg4idea.execution.HgCommandException; import java.lang.reflect.InvocationTargetException; @@ -42,7 +42,7 @@ abstract class HgAbstractGlobalAction extends AnAction { } try { command.execute(); - HgUtil.markDirectoryDirty(project,command.getRepo()); + HgUtil.markDirectoryDirty(project, command.getRepo()); } catch (HgCommandException e) { handleException(project, e); } catch (InvocationTargetException e) { diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCommandResultNotifier.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCommandResultNotifier.java index 7b2aba879952..5eaa0f5bed54 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCommandResultNotifier.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCommandResultNotifier.java @@ -19,7 +19,7 @@ import com.intellij.openapi.project.Project; import com.intellij.vcsUtil.VcsUtil; import org.apache.commons.lang.StringUtils; import org.jetbrains.annotations.Nullable; -import org.zmlx.hg4idea.HgErrorUtil; +import org.zmlx.hg4idea.util.HgErrorUtil; import org.zmlx.hg4idea.HgVcs; import org.zmlx.hg4idea.execution.HgCommandResult; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgInit.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgInit.java index e745a7b0085e..8ab3aaa6c7e1 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgInit.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgInit.java @@ -13,7 +13,7 @@ import com.intellij.openapi.vcs.VcsDirectoryMapping; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Consumer; -import org.zmlx.hg4idea.HgUtil; +import org.zmlx.hg4idea.util.HgUtil; import org.zmlx.hg4idea.HgVcs; import org.zmlx.hg4idea.HgVcsMessages; import org.zmlx.hg4idea.command.HgInitCommand; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgAddCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgAddCommand.java index 7025c7f68227..fb2445f56450 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgAddCommand.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgAddCommand.java @@ -16,7 +16,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; import org.zmlx.hg4idea.HgFile; -import org.zmlx.hg4idea.HgUtil; +import org.zmlx.hg4idea.util.HgUtil; import org.zmlx.hg4idea.execution.HgCommandExecutor; import java.util.Arrays; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgChangesetsCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgChangesetsCommand.java index 261fdda52a77..c8f1ad54d7e8 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgChangesetsCommand.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgChangesetsCommand.java @@ -20,6 +20,7 @@ import org.jetbrains.annotations.Nullable; import org.zmlx.hg4idea.HgRevisionNumber; import org.zmlx.hg4idea.execution.HgCommandExecutor; import org.zmlx.hg4idea.execution.HgCommandResult; +import org.zmlx.hg4idea.util.HgChangesetUtil; import java.util.ArrayList; import java.util.Arrays; @@ -33,8 +34,6 @@ public abstract class HgChangesetsCommand { private static final Logger LOG = Logger.getInstance(HgChangesetsCommand.class.getName()); - private static final String SEPARATOR_STRING = "\u0017"; //ascii: end of transmission block - protected final Project project; protected final String command; @@ -50,7 +49,7 @@ public abstract class HgChangesetsCommand { protected List getRevisions(VirtualFile repo) { List args = new ArrayList(Arrays.asList( "--template", - "{rev}|{node|short}|{author}|{desc|firstline}" + SEPARATOR_STRING, + HgChangesetUtil.makeTemplate("{rev}", "{node|short}", "{author}", "{desc|firstline}"), "--quiet" )); @@ -67,11 +66,11 @@ public abstract class HgChangesetsCommand { return Collections.emptyList(); } - String[] changesets = output.split(SEPARATOR_STRING); + String[] changesets = output.split(HgChangesetUtil.CHANGESET_SEPARATOR); List revisions = new ArrayList(changesets.length); for(String changeset: changesets) { - String[] parts = StringUtils.split(changeset, "|", 4); + String[] parts = StringUtils.split(changeset, HgChangesetUtil.ITEM_SEPARATOR, 4); if (parts.length == 4) { revisions.add(HgRevisionNumber.getInstance(parts[0], parts[1], parts[2], parts[3])); } else { diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgInitCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgInitCommand.java index 9043571410b0..805becdf15b2 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgInitCommand.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgInitCommand.java @@ -5,7 +5,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Consumer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.zmlx.hg4idea.HgErrorUtil; +import org.zmlx.hg4idea.util.HgErrorUtil; import org.zmlx.hg4idea.execution.HgCommandExecutor; import org.zmlx.hg4idea.execution.HgCommandResult; import org.zmlx.hg4idea.execution.HgCommandResultHandler; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgOutgoingCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgOutgoingCommand.java index a14eb43e2cac..cc045d2affd7 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgOutgoingCommand.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgOutgoingCommand.java @@ -13,6 +13,7 @@ package org.zmlx.hg4idea.command; import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; public class HgOutgoingCommand extends HgRemoteChangesetsCommand { @@ -20,4 +21,8 @@ public class HgOutgoingCommand extends HgRemoteChangesetsCommand { super(project, "outgoing"); } + protected String getRepositoryUrl(VirtualFile repo) { + return new HgShowConfigCommand(project).getDefaultPushPath(repo); + } + } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgRemoteChangesetsCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgRemoteChangesetsCommand.java index 2dedb57a86cb..702e419c1ca3 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgRemoteChangesetsCommand.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgRemoteChangesetsCommand.java @@ -19,6 +19,7 @@ import com.intellij.notification.Notification; import com.intellij.notification.NotificationListener; import com.intellij.notification.NotificationType; import com.intellij.notification.Notifications; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.options.ShowSettingsUtil; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; @@ -36,6 +37,9 @@ import java.util.List; * @author Kirill Likhodedov */ public abstract class HgRemoteChangesetsCommand extends HgChangesetsCommand { + + private static final Logger LOG = Logger.getInstance(HgRemoteChangesetsCommand.class); + public HgRemoteChangesetsCommand(Project project, String command) { super(project, command); } @@ -50,9 +54,17 @@ public abstract class HgRemoteChangesetsCommand extends HgChangesetsCommand { return true; } + protected String getRepositoryUrl(VirtualFile repo) { + return new HgShowConfigCommand(project).getDefaultPath(repo); + } + @Override protected HgCommandResult executeCommand(VirtualFile repo, List args) { - String repositoryURL = new HgShowConfigCommand(project).getDefaultPath(repo); + String repositoryURL = getRepositoryUrl(repo); + if (repositoryURL == null) { + LOG.info("executeCommand no default path configured"); + return null; + } HgCommandResult result = new HgCommandExecutor(project).executeInCurrentThread(repo, command, args); if (result == HgCommandResult.CANCELLED) { final HgVcs vcs = HgVcs.getInstance(project); diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgRemoveCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgRemoveCommand.java index 6f21cff6bcbb..802e8b88fc69 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgRemoveCommand.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgRemoveCommand.java @@ -16,7 +16,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; import org.zmlx.hg4idea.HgFile; -import org.zmlx.hg4idea.HgUtil; +import org.zmlx.hg4idea.util.HgUtil; import org.zmlx.hg4idea.execution.HgCommandExecutor; import java.util.Arrays; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgRevisionsCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgRevisionsCommand.java index 3e5ee5319ce6..eaa89a78c6c0 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgRevisionsCommand.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgRevisionsCommand.java @@ -22,7 +22,8 @@ import org.jetbrains.annotations.Nullable; import org.zmlx.hg4idea.HgFile; import org.zmlx.hg4idea.HgFileRevision; import org.zmlx.hg4idea.HgRevisionNumber; -import org.zmlx.hg4idea.HgUtil; +import org.zmlx.hg4idea.util.HgUtil; +import org.zmlx.hg4idea.util.HgChangesetUtil; import org.zmlx.hg4idea.execution.HgCommandResult; import org.zmlx.hg4idea.execution.HgCommandExecutor; @@ -33,12 +34,10 @@ import java.util.*; abstract class HgRevisionsCommand { private static final Logger LOG = Logger.getInstance(HgRevisionsCommand.class.getName()); - private static final String SEPARATOR_STRING = "\u0017"; //ascii: end of transmission block - private static final String SHORT_TEMPLATE = "{rev}|{node|short}|{parents}|{date|isodatesec}|{author}|{branches}|{desc}" + SEPARATOR_STRING; - private static final int SHORT_ITEM_COUNT = 7; - private static final String LONG_TEMPLATE = "{rev}|{node|short}|{parents}|{date|isodatesec}|{author}|{branches}|{desc}|{file_adds}|{file_mods}|{file_dels}|{file_copies}" + SEPARATOR_STRING; - private static final int LONG_ITEM_COUNT = 11; + private static final String[] SHORT_TEMPLATE_ITEMS = { "{rev}","{node|short}", "{parents}", "{date|isodatesec}", "{author}", "{branches}", "{desc}" }; + private static final String[] LONG_TEMPLATE_ITEMS = + { "{rev}", "{node|short}", "{parents}", "{date|isodatesec}", "{author}", "{branches}", "{desc}", "{file_adds}", "{file_mods}", "{file_dels}", "{file_copies}" }; private static final int REVISION_INDEX = 0; private static final int CHANGESET_INDEX = 1; @@ -73,8 +72,8 @@ abstract class HgRevisionsCommand { HgCommandExecutor hgCommandExecutor = new HgCommandExecutor(project); - String template = includeFiles ? LONG_TEMPLATE : SHORT_TEMPLATE; - int itemCount = includeFiles ? LONG_ITEM_COUNT : SHORT_ITEM_COUNT; + String template = HgChangesetUtil.makeTemplate(includeFiles ? LONG_TEMPLATE_ITEMS : SHORT_TEMPLATE_ITEMS); + int itemCount = includeFiles ? LONG_TEMPLATE_ITEMS.length : SHORT_TEMPLATE_ITEMS.length; FilePath originalFileName = HgUtil.getOriginalFileName(hgFile.toFilePath(), ChangeListManager.getInstance(project)); HgFile originalHgFile = new HgFile(hgFile.getRepo(), originalFileName); @@ -84,10 +83,10 @@ abstract class HgRevisionsCommand { List revisions = new LinkedList(); String output = result.getRawOutput(); - String[] changeSets = output.split(SEPARATOR_STRING); + String[] changeSets = output.split(HgChangesetUtil.CHANGESET_SEPARATOR); for (String line : changeSets) { try { - String[] attributes = StringUtils.splitPreserveAllTokens(line, '|'); + String[] attributes = line.split(HgChangesetUtil.ITEM_SEPARATOR); if (attributes.length != itemCount) { LOG.debug("Wrong format. Skipping line " + line); continue; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgTrackFileNamesAccrossRevisionsCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgTrackFileNamesAccrossRevisionsCommand.java index ee141ca08e9a..49e171540ebf 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgTrackFileNamesAccrossRevisionsCommand.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgTrackFileNamesAccrossRevisionsCommand.java @@ -19,16 +19,15 @@ import org.apache.commons.lang.StringUtils; import org.zmlx.hg4idea.HgFile; import org.zmlx.hg4idea.execution.HgCommandExecutor; import org.zmlx.hg4idea.execution.HgCommandResult; +import org.zmlx.hg4idea.util.HgChangesetUtil; import java.util.*; class HgTrackFileNamesAccrossRevisionsCommand { private static final Logger LOG = Logger.getInstance(HgTrackFileNamesAccrossRevisionsCommand.class.getName()); - private static final String SEPARATOR_STRING = "\u0027"; //ascii: end of transmission block - private static final String TEMPLATE = "{rev}|{file_dels}|{file_copies}" + SEPARATOR_STRING; - private static final int ITEM_COUNT = 3; + private static final String[] TEMPLATE_ITEMS = { "{rev}", "{file_dels}", "{file_copies}" }; private static final int REVISION_INDEX = 0; private static final int FILES_DELETED_INDEX = 1; @@ -48,7 +47,7 @@ class HgTrackFileNamesAccrossRevisionsCommand { arguments.add("--follow"); arguments.add("--template"); - arguments.add(TEMPLATE); + arguments.add(HgChangesetUtil.makeTemplate(TEMPLATE_ITEMS)); if (limit != -1) { arguments.add("--limit"); @@ -69,15 +68,15 @@ class HgTrackFileNamesAccrossRevisionsCommand { HgCommandResult result = execute(hgCommandExecutor, hgFile.getRepo(), limit, hgFile, currentRevision, givenRevision); String output = result.getRawOutput(); - String[] changeSets = output.split(SEPARATOR_STRING); + String[] changeSets = output.split(HgChangesetUtil.CHANGESET_SEPARATOR); String currentFileName = hgFile.getRelativePath(); // needed on windows machines currentFileName = currentFileName.replaceAll("\\\\", "/"); for (String line : changeSets) { try { - String[] attributes = StringUtils.splitPreserveAllTokens(line, '|'); - if (attributes.length != ITEM_COUNT) { + String[] attributes = line.split(HgChangesetUtil.ITEM_SEPARATOR); + if (attributes.length != TEMPLATE_ITEMS.length) { LOG.debug("Wrong format. Skipping line " + line); continue; } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgWorkingCopyRevisionsCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgWorkingCopyRevisionsCommand.java index db4e5de1ab98..263abab6aa40 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgWorkingCopyRevisionsCommand.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgWorkingCopyRevisionsCommand.java @@ -22,9 +22,10 @@ import org.apache.commons.lang.StringUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.zmlx.hg4idea.HgRevisionNumber; -import org.zmlx.hg4idea.HgUtil; +import org.zmlx.hg4idea.util.HgUtil; import org.zmlx.hg4idea.execution.HgCommandResult; import org.zmlx.hg4idea.execution.HgCommandExecutor; +import org.zmlx.hg4idea.util.HgChangesetUtil; import java.util.ArrayList; import java.util.Arrays; @@ -165,7 +166,7 @@ public class HgWorkingCopyRevisionsCommand { boolean silent) { final List args = new LinkedList(); args.add("--template"); - args.add("{rev}|{node|short}\\n"); + args.add(HgChangesetUtil.makeTemplate("{rev}", "{node|short}")); if (revision != null) { args.add("-r"); args.add(revision.getChangeset()); @@ -180,10 +181,10 @@ public class HgWorkingCopyRevisionsCommand { if (result == null) { return new ArrayList(0); } - final List lines = result.getOutputLines(); + final List lines = Arrays.asList(result.getRawOutput().split(HgChangesetUtil.CHANGESET_SEPARATOR)); final List revisions = new ArrayList(lines.size()); for(String line: lines) { - final String[] parts = StringUtils.split(line, '|'); + final String[] parts = StringUtils.split(line, HgChangesetUtil.ITEM_SEPARATOR); revisions.add(HgRevisionNumber.getInstance(parts[0], parts[1])); } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgCommandExecutor.java b/plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgCommandExecutor.java index 385e390e8b77..b7f9cbc9cf0f 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgCommandExecutor.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgCommandExecutor.java @@ -21,6 +21,7 @@ import com.intellij.vcsUtil.VcsUtil; import org.apache.commons.lang.StringUtils; import org.jetbrains.annotations.Nullable; import org.zmlx.hg4idea.*; +import org.zmlx.hg4idea.util.HgErrorUtil; import javax.swing.*; import java.awt.*; @@ -180,7 +181,11 @@ public final class HgCommandExecutor { // logging to the Version Control console (without extensions and configs) private void log(String operation, List arguments, HgCommandResult result) { - final String executable = mySettings.isRunViaBash() ? "bash -c " + HgVcs.HG_EXECUTABLE_FILE_NAME : HgVcs.HG_EXECUTABLE_FILE_NAME; + String exeName; + final int lastSlashIndex = mySettings.getHgExecutable().lastIndexOf("/"); + exeName = mySettings.getHgExecutable().substring(lastSlashIndex + 1); + + final String executable = mySettings.isRunViaBash() ? "bash -c " + exeName : exeName; final String cmdString = String.format("%s %s %s", executable, operation, StringUtils.join(arguments, " ")); // log command diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgHistoryProvider.java b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgHistoryProvider.java index a6690f64f6de..f19a2429102a 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgHistoryProvider.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgHistoryProvider.java @@ -23,7 +23,7 @@ import com.intellij.vcsUtil.VcsUtil; import org.jetbrains.annotations.Nullable; import org.zmlx.hg4idea.HgFile; import org.zmlx.hg4idea.HgFileRevision; -import org.zmlx.hg4idea.HgUtil; +import org.zmlx.hg4idea.util.HgUtil; import org.zmlx.hg4idea.command.HgLogCommand; import org.zmlx.hg4idea.command.HgWorkingCopyRevisionsCommand; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgMergeProvider.java b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgMergeProvider.java index 1d31179d512a..a21515c79577 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgMergeProvider.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgMergeProvider.java @@ -29,7 +29,7 @@ import org.jetbrains.annotations.NotNull; import org.zmlx.hg4idea.HgContentRevision; import org.zmlx.hg4idea.HgFile; import org.zmlx.hg4idea.HgRevisionNumber; -import org.zmlx.hg4idea.HgUtil; +import org.zmlx.hg4idea.util.HgUtil; import org.zmlx.hg4idea.command.HgResolveCommand; import org.zmlx.hg4idea.command.HgWorkingCopyRevisionsCommand; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/update/HgHeadMerger.java b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/update/HgHeadMerger.java index 7120af385c8d..8e710804ac44 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/update/HgHeadMerger.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/update/HgHeadMerger.java @@ -22,7 +22,7 @@ import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; import org.zmlx.hg4idea.HgChange; import org.zmlx.hg4idea.HgFile; -import org.zmlx.hg4idea.HgUtil; +import org.zmlx.hg4idea.util.HgUtil; import org.zmlx.hg4idea.HgVcs; import org.zmlx.hg4idea.execution.HgCommandResult; import org.zmlx.hg4idea.command.HgMergeCommand; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgInitDialog.java b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgInitDialog.java index 936d99151478..281c9b860a21 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgInitDialog.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgInitDialog.java @@ -24,7 +24,7 @@ import com.intellij.openapi.ui.TextFieldWithBrowseButton; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.vcsUtil.VcsUtil; import org.jetbrains.annotations.Nullable; -import org.zmlx.hg4idea.HgUtil; +import org.zmlx.hg4idea.util.HgUtil; import org.zmlx.hg4idea.HgVcsMessages; import javax.swing.*; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgChangesetUtil.java b/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgChangesetUtil.java new file mode 100644 index 000000000000..9118dc217fb9 --- /dev/null +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgChangesetUtil.java @@ -0,0 +1,48 @@ +/* + * 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.zmlx.hg4idea.util; + +import com.intellij.openapi.util.SystemInfo; + +/** + * Utilities for operations involving working with a number of changesets: log, incoming, outgoing, parents, etc. + * @author Kirill Likhodedov + */ +public class HgChangesetUtil { + + public static final String CHANGESET_SEPARATOR = "\u0003"; + public static final String ITEM_SEPARATOR = "\u0017"; + + /** + * Common method for hg commands which receive templates via --template option. + * @param templateItems template items like
{rev}
,
{node}
. + * @return items joined by ITEM_SEPARATOR, ended by CHANGESET_SEPARATOR, and, if needed (for Windows), surrounded with double-quotes. + */ + public static String makeTemplate(String... templateItems) { + StringBuilder template = new StringBuilder(); + + for (String item : templateItems) { + template.append(item).append(ITEM_SEPARATOR); + } + + template.append(CHANGESET_SEPARATOR); + if (SystemInfo.isWindows) { + return "\"" + template + "\""; + } + return template.toString(); + } + +} diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/HgErrorUtil.java b/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgErrorUtil.java similarity index 98% rename from plugins/hg4idea/src/org/zmlx/hg4idea/HgErrorUtil.java rename to plugins/hg4idea/src/org/zmlx/hg4idea/util/HgErrorUtil.java index a9c087df5035..6f328d14f6fe 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/HgErrorUtil.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgErrorUtil.java @@ -10,7 +10,7 @@ // 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.zmlx.hg4idea; +package org.zmlx.hg4idea.util; import org.apache.commons.lang.StringUtils; import org.jetbrains.annotations.Nullable; diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/HgUtil.java b/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgUtil.java similarity index 99% rename from plugins/hg4idea/src/org/zmlx/hg4idea/HgUtil.java rename to plugins/hg4idea/src/org/zmlx/hg4idea/util/HgUtil.java index 9a8c4b6fc989..2545612e5831 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/HgUtil.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgUtil.java @@ -10,7 +10,7 @@ // 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.zmlx.hg4idea; +package org.zmlx.hg4idea.util; import com.intellij.notification.Notification; import com.intellij.notification.NotificationType; @@ -31,6 +31,7 @@ import com.intellij.util.containers.HashMap; import com.intellij.vcsUtil.VcsUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.zmlx.hg4idea.*; import org.zmlx.hg4idea.command.HgRemoveCommand; import org.zmlx.hg4idea.command.HgStatusCommand; import org.zmlx.hg4idea.command.HgWorkingCopyRevisionsCommand; diff --git a/plugins/junit/src/META-INF/plugin.xml b/plugins/junit/src/META-INF/plugin.xml index 0d91587353f2..03df6e105923 100644 --- a/plugins/junit/src/META-INF/plugin.xml +++ b/plugins/junit/src/META-INF/plugin.xml @@ -40,6 +40,8 @@ + + diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/AdditionalMavenImportingSettings.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/AdditionalMavenImportingSettings.java new file mode 100644 index 000000000000..a9bb3f9ddbc6 --- /dev/null +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/AdditionalMavenImportingSettings.java @@ -0,0 +1,13 @@ +package org.jetbrains.idea.maven.project; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.options.UnnamedConfigurable; +import com.intellij.openapi.project.Project; + +public interface AdditionalMavenImportingSettings { + + ExtensionPointName EP_NAME = + ExtensionPointName.create("org.jetbrains.idea.maven.additional.importing.settings"); + + UnnamedConfigurable createConfigurable(Project project); +} diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenImportingConfigurable.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenImportingConfigurable.java index f31a4f0b19f1..d237d20b257c 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenImportingConfigurable.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenImportingConfigurable.java @@ -17,38 +17,70 @@ package org.jetbrains.idea.maven.project; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.options.SearchableConfigurable; +import com.intellij.openapi.options.UnnamedConfigurable; +import com.intellij.openapi.project.Project; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; +import java.util.ArrayList; +import java.util.List; public class MavenImportingConfigurable implements SearchableConfigurable { private final MavenImportingSettings myImportingSettings; private final MavenImportingSettingsForm mySettingsForm = new MavenImportingSettingsForm(false); + private final List myAdditionalConfigurables; - public MavenImportingConfigurable(MavenImportingSettings importingSettings) { + public MavenImportingConfigurable(Project project, MavenImportingSettings importingSettings) { myImportingSettings = importingSettings; + + myAdditionalConfigurables = new ArrayList(); + for (final AdditionalMavenImportingSettings additionalSettings : AdditionalMavenImportingSettings.EP_NAME.getExtensions()) { + myAdditionalConfigurables.add(additionalSettings.createConfigurable(project)); + } } public JComponent createComponent() { + final JPanel panel = mySettingsForm.getAdditionalSettingsPanel(); + panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); + for (final UnnamedConfigurable additionalConfigurable : myAdditionalConfigurables) { + panel.add(additionalConfigurable.createComponent()); + } return mySettingsForm.createComponent(); } public void disposeUIResources() { + for (final UnnamedConfigurable additionalConfigurable : myAdditionalConfigurables) { + additionalConfigurable.disposeUIResources(); + } } public boolean isModified() { + for (final UnnamedConfigurable additionalConfigurable : myAdditionalConfigurables) { + if (additionalConfigurable.isModified()) { + return true; + } + } + return mySettingsForm.isModified(myImportingSettings); } public void apply() throws ConfigurationException { mySettingsForm.getData(myImportingSettings); + + for (final UnnamedConfigurable additionalConfigurable : myAdditionalConfigurables) { + additionalConfigurable.apply(); + } } public void reset() { mySettingsForm.setData(myImportingSettings); + + for (final UnnamedConfigurable additionalConfigurable : myAdditionalConfigurables) { + additionalConfigurable.reset(); + } } @Nls diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenImportingSettingsForm.form b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenImportingSettingsForm.form index e06e35a38d19..d00ad63de073 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenImportingSettingsForm.form +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenImportingSettingsForm.form @@ -1,6 +1,6 @@
- + @@ -10,7 +10,7 @@ - + @@ -165,9 +165,19 @@ + + + + + + + + + + diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenImportingSettingsForm.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenImportingSettingsForm.java index 4178aca2c998..b22fbe179706 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenImportingSettingsForm.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenImportingSettingsForm.java @@ -46,6 +46,8 @@ public class MavenImportingSettingsForm { private JCheckBox myDownloadSourcesCheckBox; private JCheckBox myDownloadDocsCheckBox; + private JPanel myAdditionalSettingsPanel; + public MavenImportingSettingsForm(boolean isImportStep) { if (!isImportStep) { mySearchRecursivelyCheckBox.setVisible(false); @@ -136,4 +138,8 @@ public class MavenImportingSettingsForm { public void updateData(WizardContext wizardContext) { myProjectFormatPanel.updateData(wizardContext); } + + public JPanel getAdditionalSettingsPanel() { + return myAdditionalSettingsPanel; + } } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenSettings.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenSettings.java index f9b3479d70fb..bd2e48699545 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenSettings.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenSettings.java @@ -47,7 +47,7 @@ public class MavenSettings implements SearchableConfigurable.Parent { }; myChildren = new ArrayList(); - myChildren.add(new MavenImportingConfigurable(MavenProjectsManager.getInstance(myProject).getImportingSettings())); + myChildren.add(new MavenImportingConfigurable(myProject, MavenProjectsManager.getInstance(myProject).getImportingSettings())); myChildren.add(new MavenIgnoredFilesConfigurable(MavenProjectsManager.getInstance(myProject))); myChildren.add(new MavenRunnerConfigurable(myProject, false) { diff --git a/plugins/maven/src/main/resources/META-INF/plugin.xml b/plugins/maven/src/main/resources/META-INF/plugin.xml index fc51b0b761e6..b1ada2e25ba8 100644 --- a/plugins/maven/src/main/resources/META-INF/plugin.xml +++ b/plugins/maven/src/main/resources/META-INF/plugin.xml @@ -7,6 +7,7 @@ + diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/project/MavenSettingsTest.java b/plugins/maven/src/test/java/org/jetbrains/idea/maven/project/MavenSettingsTest.java index 8427614bab1e..b735c3043853 100644 --- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/project/MavenSettingsTest.java +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/project/MavenSettingsTest.java @@ -66,7 +66,7 @@ public class MavenSettingsTest extends MavenTestCase { public void testImportingSettings() throws Exception { assertTrue(new MavenImportingSettings().equals(new MavenImportingSettings())); - MavenImportingConfigurable importingConfigurable = new MavenImportingConfigurable(new MavenImportingSettings()); + MavenImportingConfigurable importingConfigurable = new MavenImportingConfigurable(myProject, new MavenImportingSettings()); importingConfigurable.reset(); assertFalse(importingConfigurable.isModified()); } diff --git a/plugins/properties/src/com/intellij/lang/properties/PropertiesWordCompletionFilter.java b/plugins/properties/src/com/intellij/lang/properties/PropertiesWordCompletionFilter.java index f9b71b8e5b9f..01d2430bdc33 100644 --- a/plugins/properties/src/com/intellij/lang/properties/PropertiesWordCompletionFilter.java +++ b/plugins/properties/src/com/intellij/lang/properties/PropertiesWordCompletionFilter.java @@ -27,11 +27,6 @@ import com.intellij.psi.tree.IElementType; public class PropertiesWordCompletionFilter extends DefaultWordCompletionFilter { public boolean isWordCompletionEnabledIn(final IElementType element) { - final CompletionProcess process = CompletionService.getCompletionService().getCurrentCompletion(); - if (process != null && process.isAutopopupCompletion()) { - return false; - } - return super.isWordCompletionEnabledIn(element) || element == PropertiesElementTypes.PROPERTY; } } \ No newline at end of file diff --git a/plugins/properties/src/com/intellij/lang/properties/references/PropertyReferenceBase.java b/plugins/properties/src/com/intellij/lang/properties/references/PropertyReferenceBase.java index b81b57931a3c..1ad321d84f7a 100644 --- a/plugins/properties/src/com/intellij/lang/properties/references/PropertyReferenceBase.java +++ b/plugins/properties/src/com/intellij/lang/properties/references/PropertyReferenceBase.java @@ -182,11 +182,6 @@ public abstract class PropertyReferenceBase implements PsiPolyVariantReference, @NotNull public Object[] getVariants() { - final CompletionProcess process = CompletionService.getCompletionService().getCurrentCompletion(); - if (process != null && process.isAutopopupCompletion() && isSoft()) { - return ArrayUtil.EMPTY_OBJECT_ARRAY; - } - final Set variants = new THashSet(new TObjectHashingStrategy() { public int computeHashCode(final Object object) { if (object instanceof Property) { diff --git a/plugins/relaxng/src/org/intellij/plugins/relaxNG/inspections/BaseInspection.java b/plugins/relaxng/src/org/intellij/plugins/relaxNG/inspections/BaseInspection.java index 0467ccd26912..501be380a45c 100644 --- a/plugins/relaxng/src/org/intellij/plugins/relaxNG/inspections/BaseInspection.java +++ b/plugins/relaxng/src/org/intellij/plugins/relaxNG/inspections/BaseInspection.java @@ -105,7 +105,7 @@ public abstract class BaseInspection extends XmlSuppressableInspectionTool { } @SuppressWarnings({ "SSBasedInspection" }) - public boolean isAvailable(@NotNull Project project, Editor editor, @Nullable PsiElement element) { + public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) { return super.isAvailable(project, editor, element) && getTarget(element).getText().startsWith("grammar "); } } @@ -123,7 +123,7 @@ public abstract class BaseInspection extends XmlSuppressableInspectionTool { action.invoke(project, editor, element); } - public boolean isAvailable(@NotNull Project project, Editor editor, @Nullable PsiElement element) { + public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) { return element != null && element.getContainingFile().getFileType() == StdFileTypes.XML && action.isAvailable(project, editor, element); } @@ -210,7 +210,7 @@ public abstract class BaseInspection extends XmlSuppressableInspectionTool { suppress(element.getContainingFile(), getTarget(element)); } - public boolean isAvailable(@NotNull Project project, Editor editor, @Nullable PsiElement element) { + public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) { return getTarget(element) != null; } diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/editor/UIFormEditor.java b/plugins/ui-designer/src/com/intellij/uiDesigner/editor/UIFormEditor.java index 39dd6b9c1e23..23993b22377f 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/editor/UIFormEditor.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/editor/UIFormEditor.java @@ -80,7 +80,7 @@ public final class UIFormEditor extends UserDataHolderBase implements /*Navigata } public boolean isModified(){ - return FileDocumentManager.getInstance().isFileModified(myFile); + return false; } public boolean isValid(){ diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathBinaryExpressionImpl.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathBinaryExpressionImpl.java index 675d34434f3c..ebe301e369e6 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathBinaryExpressionImpl.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathBinaryExpressionImpl.java @@ -48,7 +48,7 @@ public class XPathBinaryExpressionImpl extends XPathElementImpl implements XPath public XPathElementType getOperator() { final ASTNode[] nodes = getNode().getChildren(BINARY_OPERATIONS); final XPathElementType elementType = (XPathElementType)(nodes.length > 0 ? nodes[0].getElementType() : null); - assert elementType != null; + assert elementType != null : unexpectedPsiAssertion(); return elementType; } @@ -87,7 +87,7 @@ public class XPathBinaryExpressionImpl extends XPathElementImpl implements XPath return XPath2Type.DAYTIMEDURATION; } if (sameType(lop, rop)) { - assert lop != null; + assert lop != null : unexpectedPsiAssertion(); return lop.getType(); } diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathElementImpl.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathElementImpl.java index 96c718fc5f2a..8191b98dde5e 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathElementImpl.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathElementImpl.java @@ -20,6 +20,7 @@ import com.intellij.lang.ASTNode; import com.intellij.openapi.util.NotNullLazyValue; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElementVisitor; +import com.intellij.psi.impl.PsiTreeDebugBuilder; import com.intellij.util.IncorrectOperationException; import org.intellij.lang.xpath.XPath2ElementTypes; import org.intellij.lang.xpath.XPathElementTypes; @@ -128,6 +129,11 @@ public class XPathElementImpl extends ASTWrapperPsiElement implements XPathEleme return getContainingFile().getXPathVersion(); } + protected String unexpectedPsiAssertion() { + final PsiTreeDebugBuilder builder = new PsiTreeDebugBuilder(); + return "Unexpected PSI structure: " + builder.psiToString(this) + "--\ninside: " + builder.psiToString(getContainingFile()); + } + @Override public final void accept(@NotNull PsiElementVisitor visitor) { if (visitor instanceof XPathElementVisitor) { diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathFilterExpressionImpl.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathFilterExpressionImpl.java index edf9aa109c75..1598f0309527 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathFilterExpressionImpl.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathFilterExpressionImpl.java @@ -51,7 +51,7 @@ public class XPathFilterExpressionImpl extends XPathElementImpl implements XPath @NotNull public XPathPredicate getPredicate() { final ASTNode[] nodes = getNode().getChildren(TokenSet.create(XPathElementTypes.PREDICATE)); - assert nodes.length == 1; + assert nodes.length == 1 : unexpectedPsiAssertion(); return (XPathPredicate)nodes[0].getPsi(); } diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathFunctionCallImpl.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathFunctionCallImpl.java index e4ad35267384..466bf6ab01fe 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathFunctionCallImpl.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathFunctionCallImpl.java @@ -76,7 +76,7 @@ public class XPathFunctionCallImpl extends XPathElementImpl implements XPathFunc public String getFunctionName() { final ASTNode node = getNameNode(); final String name = node != null ? node.getText() : null; - assert name != null; + assert name != null : unexpectedPsiAssertion(); return name; } @@ -93,7 +93,7 @@ public class XPathFunctionCallImpl extends XPathElementImpl implements XPathFunc @NotNull public PrefixedName getQName() { final ASTNode node = getNameNode(); - assert node != null; + assert node != null : unexpectedPsiAssertion(); return new PrefixedNameImpl(getPrefixNode(), node); } diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathNodeTestImpl.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathNodeTestImpl.java index 47a83f94c4a9..8837dffb776b 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathNodeTestImpl.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathNodeTestImpl.java @@ -32,7 +32,7 @@ public class XPathNodeTestImpl extends XPathElementImpl implements XPathNodeTest @NotNull public XPathStep getStep() { final XPathStep step = PsiTreeUtil.getParentOfType(this, XPathStep.class); - assert step != null; + assert step != null : unexpectedPsiAssertion(); return step; } diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathPrefixExpressionImpl.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathPrefixExpressionImpl.java index 30b1047c0261..6c18090b9b5c 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathPrefixExpressionImpl.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathPrefixExpressionImpl.java @@ -49,7 +49,7 @@ public class XPathPrefixExpressionImpl extends XPathElementImpl implements XPath public XPathElementType getOperator() { final ASTNode node = getNode().findChildByType(XPathTokenTypes.ADD_OPS); final XPathElementType elementType = (XPathElementType)(node != null ? node.getElementType() : null); - assert elementType != null; + assert elementType != null : unexpectedPsiAssertion(); return elementType; } diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/validation/inspections/RedundantTypeConversion.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/validation/inspections/RedundantTypeConversion.java index c161de532549..6071f2678299 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/validation/inspections/RedundantTypeConversion.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/validation/inspections/RedundantTypeConversion.java @@ -36,7 +36,7 @@ public class RedundantTypeConversion extends XPathInspection { @NonNls private static final String SHORT_NAME = "RedundantTypeConversion"; - public boolean CHECK_ANY = true; + public boolean CHECK_ANY = false; @NotNull public String getDisplayName() { @@ -46,7 +46,7 @@ public class RedundantTypeConversion extends XPathInspection { @NotNull @NonNls public String getShortName() { - return RedundantTypeConversion.SHORT_NAME; + return SHORT_NAME; } public boolean isEnabledByDefault() { diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/associations/impl/AddAssociationAction.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/associations/impl/AddAssociationAction.java index 4ccf453edfb4..0b104a4af5c9 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/associations/impl/AddAssociationAction.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/associations/impl/AddAssociationAction.java @@ -47,7 +47,7 @@ class AddAssociationAction extends AnAction { } protected void addAssociation(AnActionEvent e, PsiFile psiFile) { - final Project project = AssociationsGroup.getProject(e); + final Project project = AssociationsGroup.getEventProject(e); if (project == null) return; final VirtualFile virtualFile = psiFile.getVirtualFile(); diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/associations/impl/AssociationsEditor.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/associations/impl/AssociationsEditor.java index cb23373a85f0..79e0c91811ba 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/associations/impl/AssociationsEditor.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/associations/impl/AssociationsEditor.java @@ -10,19 +10,22 @@ import com.intellij.ide.util.treeView.NodeDescriptor; import com.intellij.ide.util.treeView.NodeRenderer; import com.intellij.ide.util.treeView.TreeState; import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.Progressive; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.DimensionService; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.IconLoader; -import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiManager; import com.intellij.ui.LayeredIcon; +import com.intellij.ui.TreeSpeedSearch; import com.intellij.ui.components.JBList; import com.intellij.ui.treeStructure.Tree; import com.intellij.uiDesigner.core.GridConstraints; import org.intellij.lang.xpath.xslt.XsltSupport; import org.intellij.lang.xpath.xslt.associations.FileAssociationsManager; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -34,7 +37,8 @@ import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreePath; import java.awt.*; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; class AssociationsEditor { @@ -51,7 +55,7 @@ class AssociationsEditor { private final TransactionalManager myManager; private final ProjectTreeBuilder myBuilder; - public AssociationsEditor(final Project project, TreeState oldState) { + public AssociationsEditor(final Project project, final TreeState oldState) { myManager = ((FileAssociationsManagerImpl)FileAssociationsManager.getInstance(project)).getTempManager(); final DefaultActionGroup group = new DefaultActionGroup(); @@ -62,16 +66,29 @@ class AssociationsEditor { myToolbar.add(toolbar.getComponent(), new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null)); final DefaultTreeModel treeModel = new DefaultTreeModel(new DefaultMutableTreeNode()); + myTree.setModel(treeModel); + myBuilder = new ProjectTreeBuilder(project, myTree, treeModel, new MyGroupByTypeComparator(), new MyProjectStructure(project)); - myTree.setModel(treeModel); + myTree.expandRow(0); myTree.setCellRenderer(new MyNodeRenderer(myManager)); + new TreeSpeedSearch(myTree); - if (oldState == null) { - expandTree(treeModel, project, myBuilder); - } else { - oldState.applyTo(myTree); - } + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + if (oldState == null) { + expandTree(treeModel); + } else { + oldState.applyTo(myTree); + } + } + }); + } + }); myListModel = new AssociationsModel(myTree, myManager); myListModel.addListDataListener(new ListDataListener() { @@ -103,25 +120,20 @@ class AssociationsEditor { myList.getEmptyText().setText("No associated files"); } - private void expandTree(DefaultTreeModel newModel, Project project, ProjectTreeBuilder builder) { - final TreePath rootPath = new TreePath(newModel.getRoot()); - myTree.setSelectionPath(rootPath); + private void expandTree(DefaultTreeModel newModel) { + final TreePath rootPath = new TreePath(newModel.getRoot()); - final PsiManager psiManager = PsiManager.getInstance(project); - final Set files = myManager.getAssociations().keySet(); - if (files.size() > 0) { - for (VirtualFile file : files) { - builder.select(psiManager.findFile(file), file, true); - } - } else { - final Enumeration enumeration = ((DefaultMutableTreeNode)myTree.getModel().getRoot()).children(); - while (enumeration.hasMoreElements()) { - DefaultMutableTreeNode node = (DefaultMutableTreeNode)enumeration.nextElement(); - myTree.expandPath(new TreePath(node.getPath())); - } + final Object element = myBuilder.getTreeStructure().getRootElement(); + myBuilder.batch(new Progressive() { + @Override + public void run(@NotNull ProgressIndicator indicator) { + myBuilder.expand(element, null); + myBuilder.expand(myBuilder.getTreeStructure().getChildElements(element), null); } - myTree.setSelectionPath(rootPath); - myTree.scrollRectToVisible(new Rectangle(new Point(0, 0))); + }); + + myTree.setSelectionPath(rootPath); + myTree.scrollRectToVisible(new Rectangle(new Point(0, 0))); } public TreeState getState() { @@ -169,8 +181,13 @@ class AssociationsEditor { myManager.dispose(); } - public void select(PsiFile file) { - myBuilder.select(file, file.getVirtualFile(), true); + public void select(final PsiFile file) { + myBuilder.getReady(this).doWhenDone(new Runnable() { + @Override + public void run() { + myBuilder.select(file, file.getVirtualFile(), true); + } + }); } class AddAssociationActionWrapper extends AddAssociationAction { diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/associations/impl/AssociationsGroup.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/associations/impl/AssociationsGroup.java index 83d9566f92ea..9ec3a3bf98c0 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/associations/impl/AssociationsGroup.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/associations/impl/AssociationsGroup.java @@ -36,7 +36,7 @@ public class AssociationsGroup extends ActionGroup { public AnAction[] getChildren(@Nullable AnActionEvent e) { if (!isEnabled(e)) return AnAction.EMPTY_ARRAY; - final Project project = getProject(e); + final Project project = getEventProject(e); if (project == null) return AnAction.EMPTY_ARRAY; final PsiFile psiFile = getPsiFile(e); if (psiFile == null) return AnAction.EMPTY_ARRAY; @@ -69,7 +69,7 @@ public class AssociationsGroup extends ActionGroup { final PsiFile psiFile = getPsiFile(e); if (psiFile == null) return false; if (!XsltSupport.isXsltFile(psiFile)) return false; - final Project project = getProject(e); + final Project project = getEventProject(e); if (project == null) return false; return PsiManager.getInstance(project).isInProject(psiFile); } @@ -80,11 +80,6 @@ public class AssociationsGroup extends ActionGroup { return XsltSupport.isXsltFile(psiFile); } - @Nullable - static Project getProject(@Nullable AnActionEvent e) { - return e != null ? LangDataKeys.PROJECT.getData(e.getDataContext()) : null; - } - @Nullable static PsiFile getPsiFile(@Nullable AnActionEvent e) { return e != null ? LangDataKeys.PSI_FILE.getData(e.getDataContext()) : null; diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/associations/impl/ToggleAssociationAction.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/associations/impl/ToggleAssociationAction.java index 0410a9f4e0d8..7a7691498919 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/associations/impl/ToggleAssociationAction.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/associations/impl/ToggleAssociationAction.java @@ -69,6 +69,6 @@ class ToggleAssociationAction extends ToggleAction { public void setSelected(AnActionEvent e, boolean state) { assert !state; myFileAssociationsManager.removeAssociation(myPsiFile, myAssoc); - DaemonCodeAnalyzer.getInstance(AssociationsGroup.getProject(e)).restart(); + DaemonCodeAnalyzer.getInstance(AssociationsGroup.getEventProject(e)).restart(); } } diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/context/XsltQuickFixFactory.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/context/XsltQuickFixFactory.java index 424d7a5d7c1a..31fd024313ef 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/context/XsltQuickFixFactory.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/context/XsltQuickFixFactory.java @@ -19,6 +19,8 @@ import com.intellij.codeInspection.SuppressIntentionAction; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.xml.XmlFile; import com.intellij.util.IncorrectOperationException; import org.intellij.lang.xpath.psi.XPathExpression; import org.intellij.lang.xpath.psi.XPathNodeTest; @@ -84,7 +86,7 @@ public class XsltQuickFixFactory implements XPathQuickFixFactory { } protected void invokeImpl(final Project project, final PsiFile file) throws IncorrectOperationException { - FileAssociationsConfigurable.editAssociations(project, file); + FileAssociationsConfigurable.editAssociations(project, PsiTreeUtil.getContextOfType(file, XmlFile.class, false)); } @NotNull diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/XsltIncludeIndex.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/XsltIncludeIndex.java index a1720eca436d..d503c7d38428 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/XsltIncludeIndex.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/XsltIncludeIndex.java @@ -54,10 +54,15 @@ public class XsltIncludeIndex { } public static boolean processBackwardDependencies(@NotNull XmlFile file, Processor processor) { - Project project = file.getProject(); + final VirtualFile virtualFile = file.getVirtualFile(); + if (virtualFile == null) { + return true; + } + final Project project = file.getProject(); final PsiManager psiManager = PsiManager.getInstance(project); - VirtualFile[] files = FileIncludeManager.getManager(project).getIncludingFiles(file.getVirtualFile(), true); - PsiFile[] psiFiles = ContainerUtil.map2Array(files, PsiFile.class, new NullableFunction() { + + final VirtualFile[] files = FileIncludeManager.getManager(project).getIncludingFiles(virtualFile, true); + final PsiFile[] psiFiles = ContainerUtil.map2Array(files, PsiFile.class, new NullableFunction() { public PsiFile fun(VirtualFile file) { return psiManager.findFile(file); } diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/references/SelfReference.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/references/SelfReference.java index 600699a6f0be..26f18d257c2b 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/references/SelfReference.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/references/SelfReference.java @@ -37,7 +37,7 @@ class SelfReference implements PsiReference { myStartOffset = startOffset; } - public SelfReference(XmlAttribute element, PsiElement target) { + SelfReference(XmlAttribute element, PsiElement target) { this(element, target, 0); } @@ -79,4 +79,11 @@ class SelfReference implements PsiReference { public boolean isSoft() { return false; } + + public static SelfReference create(XmlAttribute element, PsiElement target) { + if (element.getValue().contains(":")) { + return new SelfReference(element, target, element.getValue().indexOf(':') + 1); + } + return new SelfReference(element, target); + } } diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/references/XsltReferenceProvider.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/references/XsltReferenceProvider.java index 3972b2469771..e1601fa35fdb 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/references/XsltReferenceProvider.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/references/XsltReferenceProvider.java @@ -1,4 +1,3 @@ - package org.intellij.lang.xpath.xslt.impl.references; import com.intellij.javaee.ExternalResourceManager; @@ -28,258 +27,262 @@ import org.intellij.lang.xpath.xslt.util.*; import org.jetbrains.annotations.NotNull; public class XsltReferenceProvider extends PsiReferenceProvider { - private static final Key> CACHED_XSLT_REFS = Key.create("CACHED_XSLT_REFS"); + private static final Key> CACHED_XSLT_REFS = Key.create("CACHED_XSLT_REFS"); - private final CachedValuesManager myCacheManager; - private final XsltElementFactory myXsltElementFactory = XsltElementFactory.getInstance(); + private final CachedValuesManager myCacheManager; + private final XsltElementFactory myXsltElementFactory = XsltElementFactory.getInstance(); - public XsltReferenceProvider(Project project) { - myCacheManager = CachedValuesManager.getManager(project); + public XsltReferenceProvider(Project project) { + myCacheManager = CachedValuesManager.getManager(project); + } + + @NotNull + public PsiReference[] getReferencesByElement(@NotNull PsiElement e, @NotNull ProcessingContext context) { + final PsiElement element = e.getParent(); + if (element instanceof XmlAttribute) { + final XmlAttribute attribute = (XmlAttribute)element; + + CachedValue cachedValue = attribute.getUserData(CACHED_XSLT_REFS); + if (cachedValue == null) { + cachedValue = myCacheManager.createCachedValue(new ReferenceProvider(attribute), false); + attribute.putUserData(CACHED_XSLT_REFS, cachedValue); + } + + final PsiReference[] value = cachedValue.getValue(); + assert value != null; + return value; + } else { + return PsiReference.EMPTY_ARRAY; + } + } + + private class ReferenceProvider implements CachedValueProvider { + private final XmlAttribute myAttribute; + + ReferenceProvider(XmlAttribute attribute) { + myAttribute = attribute; } - @NotNull - public PsiReference[] getReferencesByElement(@NotNull PsiElement e, @NotNull ProcessingContext context) { - final PsiElement element = e.getParent(); - if (element instanceof XmlAttribute) { - final XmlAttribute attribute = (XmlAttribute)element; + public Result compute() { + final PsiReference[] referencesImpl = getReferencesImpl(myAttribute); + final Object[] refs = new PsiElement[referencesImpl.length]; + for (int i = 0; i < refs.length; i++) { + refs[i] = referencesImpl[i].getElement(); + } + return new Result(referencesImpl, ArrayUtil.append(refs, myAttribute.getValueElement())); + } - CachedValue cachedValue = attribute.getUserData(CACHED_XSLT_REFS); - if (cachedValue == null) { - cachedValue = myCacheManager.createCachedValue(new ReferenceProvider(attribute), false); - attribute.putUserData(CACHED_XSLT_REFS, cachedValue); - } + private PsiReference[] getReferencesImpl(final XmlAttribute attribute) { + final PsiReference[] psiReferences; + final XmlTag tag = attribute.getParent(); - final PsiReference[] value = cachedValue.getValue(); - assert value != null; - return value; + if (XsltSupport.isTemplateCallName(attribute)) { + psiReferences = createReferencesWithPrefix(attribute, new TemplateReference(attribute)); + } else if (XsltSupport.isTemplateCallParamName(attribute)) { + final String paramName = attribute.getValue(); + final XmlTag templateCall = PsiTreeUtil.getParentOfType(tag, XmlTag.class); + + if (templateCall != null) { + if (XsltSupport.isTemplateCall(templateCall)) { + final XsltCallTemplate call = myXsltElementFactory.wrapElement(templateCall, XsltCallTemplate.class); + final ResolveUtil.Matcher matcher = new MyParamMatcher(paramName, call); + psiReferences = new PsiReference[]{ new AttributeReference(attribute, matcher, true) }; + } else if (XsltSupport.isApplyTemplates(templateCall)) { + final XsltApplyTemplates call = myXsltElementFactory.wrapElement(templateCall, XsltApplyTemplates.class); + final ResolveUtil.Matcher matcher = new MyParamMatcher2(paramName, call); + psiReferences = new PsiReference[]{ new ParamReference(attribute, matcher) }; + } else { + psiReferences = PsiReference.EMPTY_ARRAY; + } } else { - return PsiReference.EMPTY_ARRAY; + psiReferences = PsiReference.EMPTY_ARRAY; } + } else if (XsltSupport.isParam(attribute) && isInsideUnnamedTemplate(tag)) { + final XsltParameter myParam = myXsltElementFactory.wrapElement(tag, XsltParameter.class); + psiReferences = new PsiReference[]{ new MySelfReference(attribute, myParam) }; + } else if (XsltSupport.isVariableOrParamName(attribute) || XsltSupport.isTemplateName(attribute)) { + final XsltElement myElement = myXsltElementFactory.wrapElement(tag, XsltElement.class); + psiReferences = createReferencesWithPrefix(attribute, SelfReference.create(attribute, myElement)); + } else if (XsltSupport.isFunctionName(attribute)) { + final XsltFunction myElement = myXsltElementFactory.wrapElement(tag, XsltFunction.class); + psiReferences = createReferencesWithPrefix(attribute, SelfReference.create(attribute, myElement)); + } else if (XsltSupport.isIncludeOrImportHref(attribute)) { + final String href = attribute.getValue(); + final String resourceLocation = ExternalResourceManager.getInstance().getResourceLocation(href, attribute.getProject()); + //noinspection StringEquality + if (href == resourceLocation) { + // not a configured external resource + if (!href.contains("://")) { + // a local file reference + final FileReferenceSet filereferenceset = new FileReferenceSet( + href, + attribute.getValueElement(), 1, XsltReferenceProvider.this, true); + psiReferences = filereferenceset.getAllReferences(); + } else { + // external, but unknown resource + psiReferences = new PsiReference[]{ new ExternalResourceReference(attribute) }; + } + } else { + // external, known resource + psiReferences = new PsiReference[]{ new ExternalResourceReference(attribute) }; + } + } else if (XsltSupport.isMode(attribute)) { + psiReferences = ModeReference.create(attribute, XsltSupport.isTemplate(tag, false)); + } else { + psiReferences = PsiReference.EMPTY_ARRAY; + } + + return psiReferences; } - private class ReferenceProvider implements CachedValueProvider { - private final XmlAttribute myAttribute; - - ReferenceProvider(XmlAttribute attribute) { - myAttribute = attribute; - } - - public Result compute() { - final PsiReference[] referencesImpl = getReferencesImpl(myAttribute); - final Object[] refs = new PsiElement[referencesImpl.length]; - for (int i = 0; i < refs.length; i++) { - refs[i] = referencesImpl[i].getElement(); - } - return new Result(referencesImpl, ArrayUtil.append(refs, myAttribute.getValueElement())); - } - - private PsiReference[] getReferencesImpl(final XmlAttribute attribute) { - final PsiReference[] psiReferences; - final XmlTag tag = attribute.getParent(); - - if (XsltSupport.isTemplateCallName(attribute)) { - psiReferences = new PsiReference[]{ new TemplateReference(attribute) }; - } else if (XsltSupport.isTemplateCallParamName(attribute)) { - final String paramName = attribute.getValue(); - final XmlTag templateCall = PsiTreeUtil.getParentOfType(tag, XmlTag.class); - - if (templateCall != null) { - if (XsltSupport.isTemplateCall(templateCall)) { - final XsltCallTemplate call = myXsltElementFactory.wrapElement(templateCall, XsltCallTemplate.class); - final ResolveUtil.Matcher matcher = new MyParamMatcher(paramName, call); - psiReferences = new PsiReference[]{ new AttributeReference(attribute, matcher, true) }; - } else if (XsltSupport.isApplyTemplates(templateCall)) { - final XsltApplyTemplates call = myXsltElementFactory.wrapElement(templateCall, XsltApplyTemplates.class); - final ResolveUtil.Matcher matcher = new MyParamMatcher2(paramName, call); - psiReferences = new PsiReference[]{ new ParamReference(attribute, matcher) }; - } else { - psiReferences = PsiReference.EMPTY_ARRAY; - } - } else { - psiReferences = PsiReference.EMPTY_ARRAY; - } - } else if (XsltSupport.isParam(attribute) && isInsideUnnamedTemplate(tag)) { - final XsltParameter myParam = myXsltElementFactory.wrapElement(tag, XsltParameter.class); - psiReferences = new PsiReference[]{ new MySelfReference(attribute, myParam) }; - } else if (XsltSupport.isVariableOrParamName(attribute) || XsltSupport.isTemplateName(attribute)) { - final XsltElement myElement = myXsltElementFactory.wrapElement(tag, XsltElement.class); - psiReferences = new PsiReference[]{ new SelfReference(attribute, myElement) }; - } else if (XsltSupport.isFunctionName(attribute)) { - final XsltFunction myElement = myXsltElementFactory.wrapElement(tag, XsltFunction.class); - if (attribute.getValue().contains(":")) { - psiReferences = new PsiReference[]{ new PrefixReference(attribute), new SelfReference(attribute, myElement, attribute.getValue().indexOf(':') + 1) }; - } else { - psiReferences = new PsiReference[]{ new SelfReference(attribute, myElement) }; - } - } else if (XsltSupport.isIncludeOrImportHref(attribute)) { - final String href = attribute.getValue(); - final String resourceLocation = ExternalResourceManager.getInstance().getResourceLocation(href, attribute.getProject()); - //noinspection StringEquality - if (href == resourceLocation) { - // not a configured external resource - if (href.indexOf("://") == -1) { - // a local file reference - final FileReferenceSet filereferenceset = new FileReferenceSet( - href, - attribute.getValueElement(), 1, XsltReferenceProvider.this, true); - psiReferences = filereferenceset.getAllReferences(); - } else { - // external, but unknown resource - psiReferences = new PsiReference[]{ new ExternalResourceReference(attribute) }; - } - } else { - // external, known resource - psiReferences = new PsiReference[]{ new ExternalResourceReference(attribute) }; - } - } else if (XsltSupport.isMode(attribute)) { - psiReferences = ModeReference.create(attribute, XsltSupport.isTemplate(tag, false)); - } else { - psiReferences = PsiReference.EMPTY_ARRAY; - } - - return psiReferences; - } - - private class MySelfReference extends SelfReference { - private final XsltParameter myParam; - private final XmlTag myTag; - - public MySelfReference(XmlAttribute attribute, XsltParameter param) { - super(attribute, param); - myParam = param; - myTag = param.getTag(); + private PsiReference[] createReferencesWithPrefix(XmlAttribute attribute, PsiReference reference) { + if (attribute.getValue().contains(":")) { + return new PsiReference[]{ new PrefixReference(attribute), reference }; + } else { + return new PsiReference[]{ reference }; + } } + private class MySelfReference extends SelfReference { + private final XsltParameter myParam; + private final XmlTag myTag; - public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException { - if (!newElementName.equals(myParam.getName())) { - myParam.setName(newElementName); - } - final XmlAttribute attribute = myParam.getNameAttribute(); - assert attribute != null; - //noinspection ConstantConditions - return attribute.getValueElement(); - } + public MySelfReference(XmlAttribute attribute, XsltParameter param) { + super(attribute, param); + myParam = param; + myTag = param.getTag(); + } - public boolean isReferenceTo(PsiElement element) { - // self-reference is only a trick to enable rename/find usages etc. but it shouldn't actually - // refer to itself because this would list the element to be renamed/searched for twice - assert !super.isReferenceTo(element); - if (element == myParam) return false; - if (!(element instanceof XsltParameter)) return false; - - final XsltParameter param = ((XsltParameter)element); - final String name = param.getName(); - if (name == null || !name.equals(myParam.getName())) return false; - - final XsltTemplate template = XsltCodeInsightUtil.getTemplate(myTag, false); - final XsltTemplate myTemplate = XsltCodeInsightUtil.getTemplate(param.getTag(), false); - if (template == myTemplate) return true; - if (template == null || myTemplate == null) return false; - - if (!Comparing.equal(template.getMode(), myTemplate.getMode())) { - return false; - } - - final XmlFile xmlFile = (XmlFile)element.getContainingFile(); - final XmlFile myFile = (XmlFile)myParam.getContainingFile(); - if (myFile == xmlFile) return true; - - return XsltIncludeIndex.isReachableFrom(myFile, xmlFile); - } + public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException { + if (!newElementName.equals(myParam.getName())) { + myParam.setName(newElementName); } + final XmlAttribute attribute = myParam.getNameAttribute(); + assert attribute != null; + //noinspection ConstantConditions + return attribute.getValueElement(); + } + + public boolean isReferenceTo(PsiElement element) { + // self-reference is only a trick to enable rename/find usages etc. but it shouldn't actually + // refer to itself because this would list the element to be renamed/searched for twice + assert !super.isReferenceTo(element); + + if (element == myParam) return false; + if (!(element instanceof XsltParameter)) return false; + + final XsltParameter param = ((XsltParameter)element); + final String name = param.getName(); + if (name == null || !name.equals(myParam.getName())) return false; + + final XsltTemplate template = XsltCodeInsightUtil.getTemplate(myTag, false); + final XsltTemplate myTemplate = XsltCodeInsightUtil.getTemplate(param.getTag(), false); + if (template == myTemplate) return true; + if (template == null || myTemplate == null) return false; + + if (!Comparing.equal(template.getMode(), myTemplate.getMode())) { + return false; + } + + final XmlFile xmlFile = (XmlFile)element.getContainingFile(); + final XmlFile myFile = (XmlFile)myParam.getContainingFile(); + if (myFile == xmlFile) return true; + + return XsltIncludeIndex.isReachableFrom(myFile, xmlFile); + } + } + } + + private static boolean isInsideUnnamedTemplate(XmlTag tag) { + final XmlTag t = XsltCodeInsightUtil.getTemplateTag(tag, false, false); + return t != null && t.getAttribute("name", null) == null; + } + + static class MyParamMatcher extends NamedTemplateMatcher { + private final XsltCallTemplate myCall; + private final String myParamName; + private String[] myExcludedNames = ArrayUtil.EMPTY_STRING_ARRAY; + + MyParamMatcher(String paramName, XsltCallTemplate call) { + super(XsltCodeInsightUtil.getDocument(call), call.getTemplateName()); + myCall = call; + myParamName = paramName; } - private static boolean isInsideUnnamedTemplate(XmlTag tag) { - final XmlTag t = XsltCodeInsightUtil.getTemplateTag(tag, false, false); - return t != null && t.getAttribute("name", null) == null; + private MyParamMatcher(String paramName, XsltCallTemplate call, String[] excludedNames) { + super(getDocument(call), call.getTemplateName()); + myCall = call; + myParamName = paramName; + myExcludedNames = excludedNames; } - static class MyParamMatcher extends NamedTemplateMatcher { - private final XsltCallTemplate myCall; - private final String myParamName; - private String[] myExcludedNames = ArrayUtil.EMPTY_STRING_ARRAY; - - MyParamMatcher(String paramName, XsltCallTemplate call) { - super(XsltCodeInsightUtil.getDocument(call), call.getTemplateName()); - myCall = call; - myParamName = paramName; - } - - private MyParamMatcher(String paramName, XsltCallTemplate call, String[] excludedNames) { - super(getDocument(call), call.getTemplateName()); - myCall = call; - myParamName = paramName; - myExcludedNames = excludedNames; - } - - private static XmlDocument getDocument(XsltCallTemplate call) { - final XsltTemplate template = call.getTemplate(); - return XsltCodeInsightUtil.getDocument(template != null ? template : call); - } - - @Override - protected ResolveUtil.Matcher changeDocument(XmlDocument document) { - return new MyParamMatcher(myParamName, myCall, myExcludedNames); - } - - @Override - protected Result matchImpl(XmlTag element) { - if (matches(element)) { - return Result.create(new ParamMatcher(element, myExcludedNames, myParamName)); - } - return null; - } - - @Override - public ResolveUtil.Matcher variantMatcher() { - final PsiElement[] suppliedArgs = ResolveUtil.collect(new ArgumentMatcher(myCall)); - final String[] excludedNames = new String[suppliedArgs.length]; - for (int i = 0; i < suppliedArgs.length; i++) { - excludedNames[i] = ((XmlTag)suppliedArgs[i]).getAttributeValue("name"); - } - return new MyParamMatcher(null, myCall, excludedNames); - } + private static XmlDocument getDocument(XsltCallTemplate call) { + final XsltTemplate template = call.getTemplate(); + return XsltCodeInsightUtil.getDocument(template != null ? template : call); } - static class MyParamMatcher2 extends MatchTemplateMatcher { - private final String myParamName; - private final XsltApplyTemplates myCall; - private String[] myExcludedNames = ArrayUtil.EMPTY_STRING_ARRAY; - - MyParamMatcher2(String paramName, XsltApplyTemplates call) { - super(XsltCodeInsightUtil.getDocument(call), call.getMode()); - myParamName = paramName; - myCall = call; - } - - private MyParamMatcher2(String paramName, XsltApplyTemplates call, String[] excludedNames) { - this(paramName, call); - myExcludedNames = excludedNames; - } - - @Override - protected Result matchImpl(XmlTag element) { - if (matches(element)) { - return Result.create(new ParamMatcher(element, myExcludedNames, myParamName)); - } - return null; - } - - @Override - protected ResolveUtil.Matcher changeDocument(XmlDocument document) { - return new MyParamMatcher2(myParamName, myCall); - } - - @Override - public ResolveUtil.Matcher variantMatcher() { - final PsiElement[] suppliedArgs = ResolveUtil.collect(new ArgumentMatcher(myCall)); - final String[] excludedNames = new String[suppliedArgs.length]; - for (int i = 0; i < suppliedArgs.length; i++) { - excludedNames[i] = ((XmlTag)suppliedArgs[i]).getAttributeValue("name"); - } - return new MyParamMatcher2(null, myCall, excludedNames); - } + @Override + protected ResolveUtil.Matcher changeDocument(XmlDocument document) { + return new MyParamMatcher(myParamName, myCall, myExcludedNames); } + + @Override + protected Result matchImpl(XmlTag element) { + if (matches(element)) { + return Result.create(new ParamMatcher(element, myExcludedNames, myParamName)); + } + return null; + } + + @Override + public ResolveUtil.Matcher variantMatcher() { + final PsiElement[] suppliedArgs = ResolveUtil.collect(new ArgumentMatcher(myCall)); + final String[] excludedNames = new String[suppliedArgs.length]; + for (int i = 0; i < suppliedArgs.length; i++) { + excludedNames[i] = ((XmlTag)suppliedArgs[i]).getAttributeValue("name"); + } + return new MyParamMatcher(null, myCall, excludedNames); + } + } + + static class MyParamMatcher2 extends MatchTemplateMatcher { + private final String myParamName; + private final XsltApplyTemplates myCall; + private String[] myExcludedNames = ArrayUtil.EMPTY_STRING_ARRAY; + + MyParamMatcher2(String paramName, XsltApplyTemplates call) { + super(XsltCodeInsightUtil.getDocument(call), call.getMode()); + myParamName = paramName; + myCall = call; + } + + private MyParamMatcher2(String paramName, XsltApplyTemplates call, String[] excludedNames) { + this(paramName, call); + myExcludedNames = excludedNames; + } + + @Override + protected Result matchImpl(XmlTag element) { + if (matches(element)) { + return Result.create(new ParamMatcher(element, myExcludedNames, myParamName)); + } + return null; + } + + @Override + protected ResolveUtil.Matcher changeDocument(XmlDocument document) { + return new MyParamMatcher2(myParamName, myCall); + } + + @Override + public ResolveUtil.Matcher variantMatcher() { + final PsiElement[] suppliedArgs = ResolveUtil.collect(new ArgumentMatcher(myCall)); + final String[] excludedNames = new String[suppliedArgs.length]; + for (int i = 0; i < suppliedArgs.length; i++) { + excludedNames[i] = ((XmlTag)suppliedArgs[i]).getAttributeValue("name"); + } + return new MyParamMatcher2(null, myCall, excludedNames); + } + } } diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/validation/XsltXmlAnnotator.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/validation/XsltXmlAnnotator.java new file mode 100644 index 000000000000..b16e944f3cf1 --- /dev/null +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/validation/XsltXmlAnnotator.java @@ -0,0 +1,51 @@ +/* + * Copyright 2006 Sascha Weinreuter + * + * 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.intellij.lang.xpath.xslt.validation; + +import com.intellij.lang.annotation.AnnotationHolder; +import com.intellij.lang.annotation.Annotator; +import com.intellij.psi.PsiElement; +import com.intellij.psi.XmlElementVisitor; +import com.intellij.psi.xml.XmlAttribute; +import com.intellij.psi.xml.XmlAttributeValue; +import org.intellij.lang.xpath.xslt.XsltSupport; +import org.jetbrains.annotations.NotNull; + +public class XsltXmlAnnotator extends XmlElementVisitor implements Annotator { + + private AnnotationHolder myHolder; + + public void annotate(@NotNull PsiElement psiElement, @NotNull AnnotationHolder holder) { + try { + myHolder = holder; + psiElement.accept(this); + } finally { + myHolder = null; + } + } + + @Override + public void visitXmlAttributeValue(XmlAttributeValue value) { + final String s = value.getValue(); + if (s == null || s.trim().length() == 0) { + final PsiElement parent = value.getParent(); + if (parent instanceof XmlAttribute && XsltSupport.isXPathAttribute((XmlAttribute)parent)) { + myHolder.createErrorAnnotation(value, "Empty XPath expression"); + } + } + super.visitXmlAttributeValue(value); + } +} diff --git a/plugins/xpath/xpath-lang/test/org/intellij/lang/xpath/xslt/XsltHighlightingTest.java b/plugins/xpath/xpath-lang/test/org/intellij/lang/xpath/xslt/XsltHighlightingTest.java index 88d163e738e5..2db116f6d1be 100644 --- a/plugins/xpath/xpath-lang/test/org/intellij/lang/xpath/xslt/XsltHighlightingTest.java +++ b/plugins/xpath/xpath-lang/test/org/intellij/lang/xpath/xslt/XsltHighlightingTest.java @@ -15,6 +15,8 @@ */ package org.intellij.lang.xpath.xslt; +import com.intellij.codeInsight.daemon.impl.analysis.XmlUnusedNamespaceInspection; +import com.intellij.javaee.ExternalResourceManagerEx; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Computable; @@ -34,6 +36,7 @@ public class XsltHighlightingTest extends TestBase { protected void setUp() throws Exception { super.setUp(); myFixture.enableInspections(XsltStuffProvider.INSPECTION_CLASSES); + ExternalResourceManagerEx.getInstanceEx().addIgnoredResource("urn:my"); } public void xtestBackwardIncludedVariable() throws Throwable { @@ -108,6 +111,15 @@ public class XsltHighlightingTest extends TestBase { doXsltHighlighting(); } + public void testEmptyExpression() throws Throwable { + doXsltHighlighting(); + } + + public void testTemplateWithPrefix() throws Throwable { + myFixture.enableInspections(XmlUnusedNamespaceInspection.class); + doXsltHighlighting(); + } + public void xtestPerformance() throws Throwable { myFixture.configureByFile(getTestFileName() + ".xsl"); final long l = runHighlighting(); diff --git a/plugins/xpath/xpath-lang/testData/xslt/highlighting/emptyExpression.xsl b/plugins/xpath/xpath-lang/testData/xslt/highlighting/emptyExpression.xsl new file mode 100644 index 000000000000..c21e55c459df --- /dev/null +++ b/plugins/xpath/xpath-lang/testData/xslt/highlighting/emptyExpression.xsl @@ -0,0 +1,7 @@ + + + + "" /> + + + \ No newline at end of file diff --git a/plugins/xpath/xpath-lang/testData/xslt/highlighting/templateWithPrefix.xsl b/plugins/xpath/xpath-lang/testData/xslt/highlighting/templateWithPrefix.xsl new file mode 100644 index 000000000000..f7db1f52d7b7 --- /dev/null +++ b/plugins/xpath/xpath-lang/testData/xslt/highlighting/templateWithPrefix.xsl @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/plugins/xpath/xpath-view/src/META-INF/plugin.xml b/plugins/xpath/xpath-view/src/META-INF/plugin.xml index 125f30415bf6..a1de025bb314 100644 --- a/plugins/xpath/xpath-view/src/META-INF/plugin.xml +++ b/plugins/xpath/xpath-view/src/META-INF/plugin.xml @@ -119,6 +119,7 @@ + diff --git a/resources-en/src/messages/DebuggerBundle.properties b/resources-en/src/messages/DebuggerBundle.properties index 9239dd87a967..d0acc93f0c4c 100644 --- a/resources-en/src/messages/DebuggerBundle.properties +++ b/resources-en/src/messages/DebuggerBundle.properties @@ -69,7 +69,6 @@ error.vm.disconnected=VM disconnected. Target virtual machine closed connection error.unknown.host=Cannot connect to remote process, host is unknown error.cannot.open.debugger.port=Unable to open debugger port error.exception.while.connecting=Error connecting to remote process.\nException occurred: {0}\nException message: {1} -title.generic.debug.dialog=Debug status.waiting.attach=Debugger is waiting for application to start; debug address: ''{0}''; transport: ''{1}'' status.listening=Listening to the connection, address: ''{0}'', transport: ''{1}'' status.connecting=Connecting to the target VM, address: ''{0}'', transport: ''{1}'' diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index e4cd2a2d5187..cee0711237de 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -147,8 +147,6 @@ - - @@ -240,6 +238,7 @@ + @@ -496,17 +495,17 @@ Control Flow - com.intellij.codeInsight.intention.impl.AddNotNullAnnotationFix + com.intellij.codeInsight.intention.impl.AddNotNullAnnotationIntention Control Flow AddAnnotationFix - com.intellij.codeInsight.intention.impl.AddDeprecationAnnotationFix + com.intellij.codeInsight.intention.impl.AddDeprecationAnnotationIntention Control Flow AddAnnotationFix - com.intellij.codeInsight.intention.impl.AddNullableAnnotationFix + com.intellij.codeInsight.intention.impl.AddNullableAnnotationIntention Control Flow AddAnnotationFix @@ -724,8 +723,6 @@ - - - - - + + + + + + diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/DomManagerImpl.java b/xml/dom-impl/src/com/intellij/util/xml/impl/DomManagerImpl.java index 4c46c38775bb..27e7ef1d3f97 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/impl/DomManagerImpl.java +++ b/xml/dom-impl/src/com/intellij/util/xml/impl/DomManagerImpl.java @@ -1,5 +1,6 @@ package com.intellij.util.xml.impl; +import com.intellij.ide.highlighter.DomSupportEnabled; import com.intellij.ide.startup.StartupManagerEx; import com.intellij.openapi.Disposable; import com.intellij.openapi.components.ServiceManager; @@ -337,7 +338,7 @@ public final class DomManagerImpl extends DomManager { @Nullable public final DomFileElementImpl getFileElement(XmlFile file) { if (file == null) return null; - if (!StdFileTypes.XML.equals(file.getFileType())) return null; + if (!(file.getFileType() instanceof DomSupportEnabled)) return null; final VirtualFile virtualFile = file.getVirtualFile(); if (virtualFile != null && virtualFile.isDirectory()) return null; return this.getOrCreateCachedValueProvider(file).getFileElement(); diff --git a/xml/impl/src/com/intellij/codeInsight/completion/XmlTagInsertHandler.java b/xml/impl/src/com/intellij/codeInsight/completion/XmlTagInsertHandler.java index 8df86060d087..3592b78e1811 100644 --- a/xml/impl/src/com/intellij/codeInsight/completion/XmlTagInsertHandler.java +++ b/xml/impl/src/com/intellij/codeInsight/completion/XmlTagInsertHandler.java @@ -45,10 +45,7 @@ import com.intellij.psi.html.HtmlTag; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.xml.XmlTag; import com.intellij.psi.xml.XmlTokenType; -import com.intellij.xml.XmlAttributeDescriptor; -import com.intellij.xml.XmlElementDescriptor; -import com.intellij.xml.XmlElementDescriptorWithCDataContent; -import com.intellij.xml.XmlExtension; +import com.intellij.xml.*; import com.intellij.xml.actions.GenerateXmlTagAction; import com.intellij.xml.impl.schema.XmlElementDescriptorImpl; import com.intellij.xml.util.HtmlUtil; @@ -209,7 +206,7 @@ public class XmlTagInsertHandler implements InsertHandler { if (inspection != null) { StringTokenizer tokenizer = new StringTokenizer(inspection.getAdditionalEntries(0)); - notRequiredAttributes = new HashSet(1); + notRequiredAttributes = new HashSet(); while(tokenizer.hasMoreElements()) notRequiredAttributes.add(tokenizer.nextToken()); } @@ -284,22 +281,42 @@ public class XmlTagInsertHandler implements InsertHandler { else if (completionChar == ' ' && template.getSegmentsCount() == 0) { if (WebEditorOptions.getInstance().isAutomaticallyStartAttribute() && (descriptor.getAttributesDescriptors(tag).length > 0 || isTagFromHtml(tag) && !HtmlUtil.isTagWithoutAttributes(tag.getName()))) { - template.addTextSegment(" "); - template.addVariable(new MacroCallNode(new CompleteMacro()), true); - template.addTextSegment("=\""); - template.addEndVariable(); - template.addTextSegment("\""); + completeAttribute(template); return true; } } else if (completionChar == Lookup.AUTO_INSERT_SELECT_CHAR || completionChar == Lookup.NORMAL_SELECT_CHAR) { - if (WebEditorOptions.getInstance().isAutomaticallyInsertClosingTag() && - HtmlUtil.isSingleHtmlTag(tag.getName())) { - + if (WebEditorOptions.getInstance().isAutomaticallyInsertClosingTag() && HtmlUtil.isSingleHtmlTag(tag.getName())) { template.addTextSegment(tag instanceof HtmlTag ? ">" : "/>"); } else { - completeTagTail(template, descriptor, tag.getContainingFile(), tag, true); + if (needAlLeastOneAttribute(tag) && WebEditorOptions.getInstance().isAutomaticallyStartAttribute()) { + completeAttribute(template); + return true; + } + else { + completeTagTail(template, descriptor, tag.getContainingFile(), tag, true); + } + } + } + + return false; + } + + private static void completeAttribute(Template template) { + template.addTextSegment(" "); + template.addVariable(new MacroCallNode(new CompleteMacro()), true); + template.addTextSegment("=\""); + template.addEndVariable(); + template.addTextSegment("\""); + } + + private static boolean needAlLeastOneAttribute(XmlTag tag) { + for (XmlTagRuleProvider ruleProvider : XmlTagRuleProvider.EP_NAME.getExtensions()) { + for (XmlTagRuleProvider.Rule rule : ruleProvider.getTagRule(tag)) { + if (rule.needAtLeastOneAttribute(tag)) { + return true; + } } } diff --git a/xml/impl/src/com/intellij/ide/highlighter/DomSupportEnabled.java b/xml/impl/src/com/intellij/ide/highlighter/DomSupportEnabled.java new file mode 100644 index 000000000000..ff27af059112 --- /dev/null +++ b/xml/impl/src/com/intellij/ide/highlighter/DomSupportEnabled.java @@ -0,0 +1,26 @@ +/* + * 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.ide.highlighter; + +/** + * Created by IntelliJ IDEA. + * User: zajac + * Date: 15.04.11 + * Time: 14:57 + * To change this template use File | Settings | File Templates. + */ +public interface DomSupportEnabled { +} diff --git a/xml/impl/src/com/intellij/ide/highlighter/XmlFileType.java b/xml/impl/src/com/intellij/ide/highlighter/XmlFileType.java index 5b90121be6ef..1a720d69eb9d 100644 --- a/xml/impl/src/com/intellij/ide/highlighter/XmlFileType.java +++ b/xml/impl/src/com/intellij/ide/highlighter/XmlFileType.java @@ -24,7 +24,7 @@ import org.jetbrains.annotations.NotNull; import javax.swing.*; -public class XmlFileType extends XmlLikeFileType { +public class XmlFileType extends XmlLikeFileType implements DomSupportEnabled { public static final XmlFileType INSTANCE = new XmlFileType(); @NonNls public static final String DEFAULT_EXTENSION = "xml"; @NonNls public static final String DOT_DEFAULT_EXTENSION = "."+DEFAULT_EXTENSION; diff --git a/xml/impl/src/com/intellij/lang/xml/XmlWordCompletionFilter.java b/xml/impl/src/com/intellij/lang/xml/XmlWordCompletionFilter.java index 5c3ae233a136..3fbd001cb180 100644 --- a/xml/impl/src/com/intellij/lang/xml/XmlWordCompletionFilter.java +++ b/xml/impl/src/com/intellij/lang/xml/XmlWordCompletionFilter.java @@ -32,10 +32,6 @@ public class XmlWordCompletionFilter extends DefaultWordCompletionFilter { XmlTokenType.XML_ATTRIBUTE_VALUE_TOKEN, XmlTokenType.XML_DATA_CHARACTERS); public boolean isWordCompletionEnabledIn(final IElementType element) { - final CompletionProcess process = CompletionService.getCompletionService().getCurrentCompletion(); - if (process != null && process.isAutopopupCompletion()) { - return false; - } return super.isWordCompletionEnabledIn(element) || ENABLED_TOKENS.contains(element); } } \ No newline at end of file diff --git a/xml/impl/src/com/intellij/xml/util/TagSetRuleProvider.java b/xml/impl/src/com/intellij/xml/util/TagSetRuleProvider.java new file mode 100644 index 000000000000..e4e20b9ac570 --- /dev/null +++ b/xml/impl/src/com/intellij/xml/util/TagSetRuleProvider.java @@ -0,0 +1,68 @@ +/* + * 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.xml.util; + +import com.intellij.psi.xml.XmlTag; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * @author Sergey Evdokimov + */ +public abstract class TagSetRuleProvider extends XmlTagRuleProviderBase { + + private final Map map = Collections.synchronizedMap(new HashMap()); + + @Nullable + protected abstract String getNamespace(@NotNull XmlTag tag); + + protected abstract void initMap(TagsRuleMap map, @NotNull String version); + + @Override + public Rule[] getTagRule(@NotNull XmlTag tag) { + String namespace = getNamespace(tag); + if (namespace == null) return Rule.EMPTY_ARRAY; + + return getTagRule(tag, namespace); + } + + public Rule[] getTagRule(@NotNull XmlTag tag, String namespace) { + TagsRuleMap ruleMap = map.get(namespace); + if (ruleMap == null) { + ruleMap = new TagsRuleMap(); + initMap(ruleMap, namespace); + map.put(namespace, ruleMap); + } + + String tagName = tag.getLocalName(); + Rule[] rules = ruleMap.get(tagName); + if (rules == null) return Rule.EMPTY_ARRAY; + + return rules; + } + + protected static class TagsRuleMap extends HashMap { + public void add(String tagName, Rule ... rules) { + assert rules.length > 0; + Rule[] oldValue = put(tagName, rules); + assert oldValue == null; + } + } +} diff --git a/xml/impl/src/com/intellij/xml/util/XmlTagRuleProviderBase.java b/xml/impl/src/com/intellij/xml/util/XmlTagRuleProviderBase.java new file mode 100644 index 000000000000..c5953c453aba --- /dev/null +++ b/xml/impl/src/com/intellij/xml/util/XmlTagRuleProviderBase.java @@ -0,0 +1,239 @@ +/* + * 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.xml.util; + +import com.intellij.codeInsight.daemon.impl.analysis.InsertRequiredAttributeFix; +import com.intellij.codeInspection.LocalQuickFix; +import com.intellij.codeInspection.ProblemHighlightType; +import com.intellij.codeInspection.ProblemsHolder; +import com.intellij.codeInspection.htmlInspections.RemoveAttributeIntentionAction; +import com.intellij.lang.ASTNode; +import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiElement; +import com.intellij.psi.tree.RoleFinder; +import com.intellij.psi.xml.XmlAttribute; +import com.intellij.psi.xml.XmlChildRole; +import com.intellij.psi.xml.XmlElement; +import com.intellij.psi.xml.XmlTag; +import com.intellij.util.ArrayUtil; +import com.intellij.xml.XmlTagRuleProvider; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public abstract class XmlTagRuleProviderBase extends XmlTagRuleProvider { + + public static RequireAttributeOneOf requireAttr(String ... attributeNames) { + return new RequireAttributeOneOf(attributeNames); + } + + public static ShouldHaveParams shouldHaveParams() { + return new ShouldHaveParams(); + } + + public static Rule unusedIfPresent(String attrPresent, String ... attrUnused) { + Effect[] effects = new Effect[attrUnused.length]; + for (int i = 0; i < effects.length; i++) { + effects[i] = unused(attrUnused[i], "The attribute '" + attrUnused[i] + "' is unused because the attribute '" + attrPresent + "' is present"); + } + + return new ConditionRule(ifAttrPresent(attrPresent), effects); + } + + public static Rule unusedAllIfPresent(String attrPresent, String ... attrUnused) { + return new ConditionRule(ifAttrPresent(attrPresent), + new InvalidAllExpectSome("The attribute is unused because the attribute " + attrPresent + " is present", + ProblemHighlightType.LIKE_UNUSED_SYMBOL, + ArrayUtil.append(attrUnused, attrPresent))); + } + + public static Effect invalid(String attrName, String text) { + return new InvalidAttrEffect(attrName, text, ProblemHighlightType.GENERIC_ERROR_OR_WARNING); + } + + public static Effect unused(String attrName) { + return new InvalidAttrEffect(attrName, "Attribute '" + attrName + "' is unused", ProblemHighlightType.LIKE_UNUSED_SYMBOL); + } + + public static Effect unused(String attrName, String text) { + return new InvalidAttrEffect(attrName, text, ProblemHighlightType.LIKE_UNUSED_SYMBOL); + } + + public static Effect unusedAll(String text, String... attrNames) { + return new InvalidAllExpectSome(text, ProblemHighlightType.LIKE_UNUSED_SYMBOL, attrNames); + } + + public static Rule rule(Condition condition, Effect ... effect) { + return new ConditionRule(condition, effect); + } + + @Nullable + public static PsiElement getXmlElement(RoleFinder roleFinder, XmlElement tag) { + ASTNode tagNode = tag.getNode(); + if (tagNode == null) return null; + + ASTNode nameElement = roleFinder.findChild(tagNode); + if (nameElement == null) return null; + + return nameElement.getPsi(); + } + + @Nullable + public static PsiElement getTagNameElement(XmlTag tag) { + return getXmlElement(XmlChildRole.START_TAG_NAME_FINDER, tag); + } + + @Nullable + public static PsiElement getAttributeNameElement(XmlAttribute attribute) { + return getXmlElement(XmlChildRole.ATTRIBUTE_NAME_FINDER, attribute); + } + + public static boolean isClosedTag(XmlTag tag) { + return getXmlElement(XmlChildRole.EMPTY_TAG_END_FINDER, tag) != null || getXmlElement(XmlChildRole.CLOSING_TAG_START_FINDER, tag) != null; + } + + public static Condition ifAttrPresent(final String attrName) { + return new Condition() { + @Override + public boolean value(XmlTag tag) { + return tag.getAttribute(attrName) != null; + } + }; + } + + // ---=== Classes ===--- + + public static abstract class Effect { + public abstract void annotate(@NotNull XmlTag tag, ProblemsHolder holder); + } + + public static class InvalidAttrEffect extends Effect { + private final String myAttrName; + private final String myText; + private final ProblemHighlightType myType; + + public InvalidAttrEffect(String attrName, String text, ProblemHighlightType type) { + myAttrName = attrName; + myText = text; + myType = type; + } + + @Override + public void annotate(@NotNull XmlTag tag, ProblemsHolder holder) { + XmlAttribute attribute = tag.getAttribute(myAttrName); + if (attribute != null) { + PsiElement attributeNameElement = getAttributeNameElement(attribute); + if (attributeNameElement != null) { + holder.registerProblem(attributeNameElement, myText, myType, new RemoveAttributeIntentionAction(myAttrName)); + } + } + } + } + + public static class InvalidAllExpectSome extends Effect { + private final String[] myAttrNames; + private final String myText; + private final ProblemHighlightType myType; + + public InvalidAllExpectSome(String text, ProblemHighlightType type, String... attrNames) { + myAttrNames = attrNames; + myText = text; + myType = type; + } + + @Override + public void annotate(@NotNull XmlTag tag, ProblemsHolder holder) { + for (XmlAttribute xmlAttribute : tag.getAttributes()) { + String attrName = xmlAttribute.getName(); + if (!ArrayUtil.contains(attrName, myAttrNames)) { + PsiElement attributeNameElement = getAttributeNameElement(xmlAttribute); + if (attributeNameElement != null) { + holder.registerProblem(attributeNameElement, myText, myType, new RemoveAttributeIntentionAction(attrName)); + } + } + } + } + } + + public static class ConditionRule extends Rule { + private final Condition myCondition; + private final Effect[] myEffect; + + public ConditionRule(Condition condition, Effect ... effect) { + this.myCondition = condition; + this.myEffect = effect; + } + + @Override + public void annotate(@NotNull XmlTag tag, ProblemsHolder holder) { + if (myCondition.value(tag)) { + for (Effect effect : myEffect) { + effect.annotate(tag, holder); + } + } + } + } + + public static class ShouldHaveParams extends Rule { + @Override + public boolean needAtLeastOneAttribute(@NotNull XmlTag tag) { + return true; + } + } + + public static class RequireAttributeOneOf extends ShouldHaveParams { + private final String[] myAttributeNames; + private final ProblemHighlightType myProblemHighlightType; + + public RequireAttributeOneOf(String ... attributeNames) { + myAttributeNames = attributeNames; + myProblemHighlightType = ProblemHighlightType.GENERIC_ERROR_OR_WARNING; + } + + public RequireAttributeOneOf(@NotNull ProblemHighlightType problemHighlightType, String... attributeNames) { + assert attributeNames.length > 0; + myAttributeNames = attributeNames; + myProblemHighlightType = problemHighlightType; + } + + public String[] getAttributeNames() { + return myAttributeNames; + } + + @Override + public void annotate(@NotNull XmlTag tag, ProblemsHolder holder) { + for (String attributeName : myAttributeNames) { + if (tag.getAttribute(attributeName) != null) { + return; + } + } + + if (!isClosedTag(tag)) return; + + PsiElement tagNameElement = getTagNameElement(tag); + if (tagNameElement == null) return; + + LocalQuickFix[] fixes = new LocalQuickFix[myAttributeNames.length]; + for (int i = 0; i < myAttributeNames.length; i++) { + fixes[i] = new InsertRequiredAttributeFix(tag, myAttributeNames[i], null); + } + + holder.registerProblem(tagNameElement, "Tag should have one of following attributes: " + StringUtil.join(myAttributeNames, ", "), + myProblemHighlightType, + fixes); + } + } +} diff --git a/xml/openapi/src/com/intellij/xml/XmlTagRuleProvider.java b/xml/openapi/src/com/intellij/xml/XmlTagRuleProvider.java new file mode 100644 index 000000000000..69d3bbef1951 --- /dev/null +++ b/xml/openapi/src/com/intellij/xml/XmlTagRuleProvider.java @@ -0,0 +1,42 @@ +/* + * 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.xml; + +import com.intellij.codeInspection.ProblemsHolder; +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.psi.xml.XmlTag; +import org.jetbrains.annotations.NotNull; + +public abstract class XmlTagRuleProvider { + + public static final ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.xml.xmlTagRuleProvider"); + + public abstract Rule[] getTagRule(@NotNull XmlTag tag); + + public static class Rule { + + public static final Rule[] EMPTY_ARRAY = new Rule[0]; + + public void annotate(@NotNull XmlTag tag, ProblemsHolder holder) { + + } + + public boolean needAtLeastOneAttribute(@NotNull XmlTag tag) { + return false; + } + } + +}