mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote branch 'origin/master'
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2011 JetBrains s.r.o.
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -34,6 +34,7 @@ import com.intellij.openapi.ui.popup.JBPopupFactory;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.Iconable;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vcs.FileStatus;
|
||||
import com.intellij.openapi.vcs.FileStatusManager;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
@@ -43,10 +44,8 @@ import com.intellij.openapi.wm.ToolWindowManager;
|
||||
import com.intellij.openapi.wm.ex.WindowManagerEx;
|
||||
import com.intellij.openapi.wm.impl.IdeFrameImpl;
|
||||
import com.intellij.openapi.wm.impl.ToolWindowManagerImpl;
|
||||
import com.intellij.ui.ColoredListCellRenderer;
|
||||
import com.intellij.ui.Gray;
|
||||
import com.intellij.ui.IdeBorderFactory;
|
||||
import com.intellij.ui.SimpleTextAttributes;
|
||||
import com.intellij.openapi.wm.impl.content.GraphicsConfig;
|
||||
import com.intellij.ui.*;
|
||||
import com.intellij.ui.components.JBList;
|
||||
import com.intellij.util.Alarm;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
@@ -62,6 +61,8 @@ import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
@@ -121,10 +122,12 @@ public class Switcher extends AnAction implements DumbAware {
|
||||
ToolWindow tw;
|
||||
if (SWITCHER != null && event instanceof KeyEvent) {
|
||||
final KeyEvent keyEvent = (KeyEvent)event;
|
||||
if (event.getID() == KEY_RELEASED && keyEvent.getKeyCode() == CTRL_KEY && UISettings.getInstance().HIDE_SWITCHER_ON_CONTROL_RELEASE) {
|
||||
if (event.getID() == KEY_RELEASED && keyEvent.getKeyCode() == CTRL_KEY && isAutoHide()) {
|
||||
SwingUtilities.invokeLater(CHECKER);
|
||||
}
|
||||
else if (event.getID() == KEY_PRESSED && (tw = SWITCHER.twShortcuts.get(String.valueOf((char)keyEvent.getKeyCode()))) != null) {
|
||||
else if (isAutoHide()
|
||||
&& event.getID() == KEY_PRESSED
|
||||
&& (tw = SWITCHER.twShortcuts.get(String.valueOf((char)keyEvent.getKeyCode()))) != null) {
|
||||
SWITCHER.myPopup.closeOk(null);
|
||||
tw.activate(null, true, true);
|
||||
}
|
||||
@@ -176,6 +179,7 @@ public class Switcher extends AnAction implements DumbAware {
|
||||
final Project project;
|
||||
final Map<String, ToolWindow> twShortcuts;
|
||||
final Alarm myAlarm;
|
||||
final SwitcherSpeedSearch mySpeedSearch = isAutoHide() ? null : new SwitcherSpeedSearch();
|
||||
|
||||
@SuppressWarnings({"ManualArrayToCollectionCopy"})
|
||||
SwitcherPanel(Project project) {
|
||||
@@ -225,7 +229,7 @@ public class Switcher extends AnAction implements DumbAware {
|
||||
toolWindows = new JBList(twModel);
|
||||
toolWindows.setBorder(IdeBorderFactory.createEmptyBorder(5, 5, 5, 20));
|
||||
toolWindows.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
toolWindows.setCellRenderer(new SwitcherToolWindowsListRenderer(ids, map) {
|
||||
toolWindows.setCellRenderer(new SwitcherToolWindowsListRenderer(mySpeedSearch, ids, map) {
|
||||
@Override
|
||||
public Component getListCellRendererComponent(JList list,
|
||||
Object value,
|
||||
@@ -297,7 +301,7 @@ public class Switcher extends AnAction implements DumbAware {
|
||||
files = new JBList(filesModel);
|
||||
files.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
files.setBorder(IdeBorderFactory.createEmptyBorder(5, 5, 5, 20));
|
||||
files.setCellRenderer(new VirtualFilesRenderer(project) {
|
||||
files.setCellRenderer(new VirtualFilesRenderer(project, mySpeedSearch) {
|
||||
@Override
|
||||
public Component getListCellRendererComponent(JList list,
|
||||
Object value,
|
||||
@@ -381,19 +385,33 @@ public class Switcher extends AnAction implements DumbAware {
|
||||
.setRequestFocus(true)
|
||||
.setTitle(SWITCHER_TITLE)
|
||||
.setMovable(false)
|
||||
.setCancelKeyEnabled(false)
|
||||
.setCancelCallback(new Computable<Boolean>() {
|
||||
public Boolean compute() {
|
||||
SWITCHER = null;
|
||||
return true;
|
||||
}
|
||||
}).createPopup();
|
||||
public Boolean compute() {
|
||||
SWITCHER = null;
|
||||
return true;
|
||||
}
|
||||
}).createPopup();
|
||||
|
||||
new AnAction(null, null, null){
|
||||
if (!isAutoHide()) {
|
||||
new AnAction(null, null, null) {
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
//suppress all actions to activate a toolwindow : IDEA-71277
|
||||
}
|
||||
}.registerCustomShortcutSet(TW_SHORTCUT, this, myPopup);
|
||||
new AnAction(null, null, null) {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
if (mySpeedSearch != null && mySpeedSearch.isPopupActive()) {
|
||||
mySpeedSearch.hidePopup();
|
||||
} else {
|
||||
myPopup.cancel();
|
||||
}
|
||||
}
|
||||
}.registerCustomShortcutSet(CustomShortcutSet.fromString("ESCAPE"), this, myPopup);
|
||||
}
|
||||
|
||||
Component comp = null;
|
||||
final EditorWindow result = FileEditorManagerEx.getInstanceEx(project).getActiveWindow().getResult();
|
||||
@@ -407,6 +425,7 @@ public class Switcher extends AnAction implements DumbAware {
|
||||
myPopup.showInCenterOf(comp);
|
||||
}
|
||||
|
||||
|
||||
private Map<String, ToolWindow> createShortcuts(List<ToolWindow> windows) {
|
||||
final Map<String, ToolWindow> keymap = new HashMap<String, ToolWindow>(windows.size());
|
||||
final List<ToolWindow> pluginToolWindows = new ArrayList<ToolWindow>();
|
||||
@@ -441,7 +460,7 @@ public class Switcher extends AnAction implements DumbAware {
|
||||
}
|
||||
|
||||
public void keyReleased(KeyEvent e) {
|
||||
if ((e.getKeyCode() == CTRL_KEY && UISettings.getInstance().HIDE_SWITCHER_ON_CONTROL_RELEASE)
|
||||
if ((e.getKeyCode() == CTRL_KEY && isAutoHide())
|
||||
|| e.getKeyCode() == VK_ENTER) {
|
||||
navigate();
|
||||
} else
|
||||
@@ -453,6 +472,8 @@ public class Switcher extends AnAction implements DumbAware {
|
||||
}
|
||||
|
||||
public void keyPressed(KeyEvent e) {
|
||||
if (mySpeedSearch != null && mySpeedSearch.isPopupActive()) return;
|
||||
|
||||
switch (e.getKeyCode()) {
|
||||
case VK_UP:
|
||||
goBack();
|
||||
@@ -546,7 +567,7 @@ public class Switcher extends AnAction implements DumbAware {
|
||||
}
|
||||
|
||||
private void goRight() {
|
||||
if ((isFilesSelected() || !isFilesVisible()) && UISettings.getInstance().HIDE_SWITCHER_ON_CONTROL_RELEASE) {
|
||||
if ((isFilesSelected() || !isFilesVisible()) && isAutoHide()) {
|
||||
cancel();
|
||||
}
|
||||
else {
|
||||
@@ -562,7 +583,7 @@ public class Switcher extends AnAction implements DumbAware {
|
||||
}
|
||||
|
||||
private void goLeft() {
|
||||
if (isToolWindowsSelected() && UISettings.getInstance().HIDE_SWITCHER_ON_CONTROL_RELEASE) {
|
||||
if (isToolWindowsSelected() && isAutoHide()) {
|
||||
cancel();
|
||||
}
|
||||
else {
|
||||
@@ -699,26 +720,102 @@ public class Switcher extends AnAction implements DumbAware {
|
||||
repaintLists();
|
||||
}
|
||||
public void mouseDragged(MouseEvent e) {}
|
||||
|
||||
private class SwitcherSpeedSearch extends SpeedSearchBase<SwitcherPanel> implements PropertyChangeListener {
|
||||
private Object[] myElements;
|
||||
|
||||
public SwitcherSpeedSearch() {
|
||||
super(SwitcherPanel.this);
|
||||
addChangeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getSelectedIndex() {
|
||||
return isFilesSelected()
|
||||
? files.getSelectedIndex()
|
||||
: files.getModel().getSize() + toolWindows.getSelectedIndex();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object[] getAllElements() {
|
||||
if (myElements == null) {
|
||||
final SwitcherPanel switcher = SwitcherPanel.this;
|
||||
final Object[] files = ((DefaultListModel)switcher.files.getModel()).toArray();
|
||||
final Object[] toolWindows = ((DefaultListModel)switcher.toolWindows.getModel()).toArray();
|
||||
myElements = new Object[files.length + toolWindows.length];
|
||||
System.arraycopy(files, 0, myElements, 0, files.length);
|
||||
System.arraycopy(toolWindows, 0, myElements, files.length, toolWindows.length);
|
||||
}
|
||||
return myElements;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected String getElementText(Object element) {
|
||||
return element instanceof ToolWindow
|
||||
? ids.get(element)
|
||||
: element instanceof FileInfo
|
||||
? ((FileInfo)element).getFirst().getName() : "";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void selectElement(Object element, String selectedText) {
|
||||
if (element instanceof FileInfo) {
|
||||
toolWindows.getSelectionModel().clearSelection();
|
||||
files.setSelectedValue(element, false);
|
||||
} else {
|
||||
files.clearSelection();
|
||||
toolWindows.setSelectedValue(element, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
files.repaint();
|
||||
toolWindows.repaint();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isAutoHide() {
|
||||
return UISettings.getInstance().HIDE_SWITCHER_ON_CONTROL_RELEASE;
|
||||
}
|
||||
|
||||
private static class VirtualFilesRenderer extends ColoredListCellRenderer {
|
||||
private final Project myProject;
|
||||
private final SpeedSearchBase mySearch;
|
||||
private boolean hide = false;
|
||||
|
||||
public VirtualFilesRenderer(Project project) {
|
||||
public VirtualFilesRenderer(Project project, SpeedSearchBase search) {
|
||||
myProject = project;
|
||||
mySearch = search;
|
||||
}
|
||||
|
||||
protected void customizeCellRenderer(JList list, Object value, int index, boolean selected, boolean hasFocus) {
|
||||
hide = false;
|
||||
if (value instanceof FileInfo) {
|
||||
final VirtualFile virtualFile = ((FileInfo)value).first;
|
||||
final String name = virtualFile.getPresentableName();
|
||||
setIcon(IconUtil.getIcon(virtualFile, Iconable.ICON_FLAG_READ_STATUS, myProject));
|
||||
|
||||
if ( mySearch != null && mySearch.isPopupActive()) {
|
||||
hide = mySearch.matchingFragments(name) == null && !StringUtil.isEmpty(mySearch.getEnteredPrefix());
|
||||
}
|
||||
final FileStatus fileStatus = FileStatusManager.getInstance(myProject).getStatus(virtualFile);
|
||||
final TextAttributes attributes = new TextAttributes(fileStatus.getColor(), null, null, EffectType.LINE_UNDERSCORE, Font.PLAIN);
|
||||
append(name, SimpleTextAttributes.fromTextAttributes(attributes));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPaint(Graphics2D g) {
|
||||
GraphicsConfig config = new GraphicsConfig(g);
|
||||
if (hide) {
|
||||
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.4f));
|
||||
}
|
||||
super.doPaint(g);
|
||||
config.restore();
|
||||
}
|
||||
}
|
||||
|
||||
private static class FileInfo extends Pair<VirtualFile, EditorWindow> {
|
||||
|
||||
+33
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2011 JetBrains s.r.o.
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,11 +15,15 @@
|
||||
*/
|
||||
package com.intellij.ide.actions;
|
||||
|
||||
import com.intellij.ide.ui.UISettings;
|
||||
import com.intellij.openapi.editor.markup.EffectType;
|
||||
import com.intellij.openapi.editor.markup.TextAttributes;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.wm.ToolWindow;
|
||||
import com.intellij.openapi.wm.impl.content.GraphicsConfig;
|
||||
import com.intellij.ui.ColoredListCellRenderer;
|
||||
import com.intellij.ui.SimpleTextAttributes;
|
||||
import com.intellij.ui.SpeedSearchBase;
|
||||
import com.intellij.util.PlatformIcons;
|
||||
|
||||
import javax.swing.*;
|
||||
@@ -34,26 +38,51 @@ import java.util.Map;
|
||||
class SwitcherToolWindowsListRenderer extends ColoredListCellRenderer {
|
||||
private static final Map<String, Icon> iconCache = new HashMap<String, Icon>();
|
||||
private static final SimpleTextAttributes ID_STYLE = new SimpleTextAttributes(SimpleTextAttributes.STYLE_UNDERLINE, Color.black);
|
||||
private final SpeedSearchBase mySpeedSearch;
|
||||
private final Map<ToolWindow, String> ids;
|
||||
private final Map<ToolWindow, String> shortcuts;
|
||||
private boolean hide = false;
|
||||
|
||||
SwitcherToolWindowsListRenderer(Map<ToolWindow, String> ids, Map<ToolWindow, String> shortcuts) {
|
||||
SwitcherToolWindowsListRenderer(SpeedSearchBase speedSearch,
|
||||
Map<ToolWindow, String> ids,
|
||||
Map<ToolWindow, String> shortcuts) {
|
||||
mySpeedSearch = speedSearch;
|
||||
this.ids = ids;
|
||||
this.shortcuts = shortcuts;
|
||||
}
|
||||
|
||||
protected void customizeCellRenderer(JList list, Object value, int index, boolean selected, boolean hasFocus) {
|
||||
hide = false;
|
||||
if (value instanceof ToolWindow) {
|
||||
final ToolWindow tw = (ToolWindow)value;
|
||||
setIcon(getIcon(tw));
|
||||
append(shortcuts.get(tw), ID_STYLE);
|
||||
final String name = ": " + ids.get(tw);
|
||||
final String name;
|
||||
|
||||
if (UISettings.getInstance().HIDE_SWITCHER_ON_CONTROL_RELEASE) {
|
||||
append(shortcuts.get(tw), ID_STYLE);
|
||||
name = ": " + ids.get(tw);
|
||||
} else {
|
||||
name = ids.get(tw);
|
||||
}
|
||||
|
||||
final TextAttributes attributes = new TextAttributes(Color.BLACK, null, null, EffectType.LINE_UNDERSCORE, Font.PLAIN);
|
||||
append(name, SimpleTextAttributes.fromTextAttributes(attributes));
|
||||
if (mySpeedSearch != null && mySpeedSearch.isPopupActive()) {
|
||||
hide = mySpeedSearch.matchingFragments(ids.get(tw)) == null && !StringUtil.isEmpty(mySpeedSearch.getEnteredPrefix());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPaint(Graphics2D g) {
|
||||
GraphicsConfig config = new GraphicsConfig(g);
|
||||
if (hide) {
|
||||
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.4f));
|
||||
}
|
||||
super.doPaint(g);
|
||||
config.restore();
|
||||
}
|
||||
|
||||
private Icon getIcon(ToolWindow toolWindow) {
|
||||
Icon icon = iconCache.get(ids.get(toolWindow));
|
||||
if (icon != null) return icon;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,6 +17,7 @@ package com.intellij.ui;
|
||||
|
||||
import com.intellij.featureStatistics.FeatureUsageTracker;
|
||||
import com.intellij.ide.DataManager;
|
||||
import com.intellij.ide.ui.UISettings;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.CustomShortcutSet;
|
||||
@@ -198,6 +199,15 @@ public abstract class SpeedSearchBase<Comp extends JComponent> extends SpeedSear
|
||||
final Object element = it.next();
|
||||
if (isMatchingElement(element, _s)) return element;
|
||||
}
|
||||
|
||||
if (UISettings.getInstance().CYCLE_SCROLLING) {
|
||||
final ListIterator<Object> i = getElementIterator(0);
|
||||
while (i.hasNext()) {
|
||||
final Object element = i.next();
|
||||
if (isMatchingElement(element, _s)) return element;
|
||||
}
|
||||
}
|
||||
|
||||
return ( current != null && isMatchingElement(current, _s) ) ? current : null;
|
||||
}
|
||||
|
||||
@@ -217,6 +227,15 @@ public abstract class SpeedSearchBase<Comp extends JComponent> extends SpeedSear
|
||||
final Object element = it.previous();
|
||||
if (isMatchingElement(element, _s)) return element;
|
||||
}
|
||||
|
||||
if (UISettings.getInstance().CYCLE_SCROLLING) {
|
||||
final ListIterator<Object> i = getElementIterator(getAllElements().length);
|
||||
while (i.hasPrevious()) {
|
||||
final Object element = i.previous();
|
||||
if (isMatchingElement(element, _s)) return element;
|
||||
}
|
||||
}
|
||||
|
||||
return selectedIndex != -1 && isMatchingElement(current, _s) ? current : null;
|
||||
}
|
||||
|
||||
|
||||
+39
-24
@@ -18,9 +18,7 @@ package org.jetbrains.plugins.groovy.codeInspection.noReturnMethod;
|
||||
import com.intellij.codeInspection.ProblemsHolder;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import com.intellij.psi.PsiType;
|
||||
import com.intellij.psi.*;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -65,14 +63,33 @@ public class MissingReturnInspection extends GroovySuppressableInspectionTool {
|
||||
return GroovyInspectionBundle.message("no.return.display.name");
|
||||
}
|
||||
|
||||
public enum ReturnStatus {
|
||||
mustReturnValue, shouldReturnValue, shouldNotReturnValue;
|
||||
|
||||
public static ReturnStatus getReturnStatus(PsiElement subject) {
|
||||
if (subject instanceof GrClosableBlock) {
|
||||
final PsiType inferredReturnType = GroovyExpectedTypesProvider.getExpectedClosureReturnType((GrClosableBlock)subject);
|
||||
if (inferredReturnType instanceof PsiClassType) {
|
||||
PsiClass resolved = ((PsiClassType)inferredReturnType).resolve();
|
||||
if (resolved != null && !(resolved instanceof PsiTypeParameter)) return mustReturnValue;
|
||||
}
|
||||
return inferredReturnType != null && inferredReturnType != PsiType.VOID ? shouldReturnValue : shouldNotReturnValue;
|
||||
}
|
||||
else if (subject instanceof GrMethod) {
|
||||
return ((GrMethod)subject).getReturnTypeElementGroovy() != null && ((GrMethod)subject).getReturnType() != PsiType.VOID
|
||||
? mustReturnValue
|
||||
: shouldNotReturnValue;
|
||||
}
|
||||
return shouldNotReturnValue;
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder problemsHolder, boolean onTheFly) {
|
||||
return new GroovyPsiElementVisitor(new GroovyElementVisitor() {
|
||||
public void visitClosure(GrClosableBlock closure) {
|
||||
super.visitClosure(closure);
|
||||
|
||||
final PsiType expectedClosureType = GroovyExpectedTypesProvider.getExpectedClosureReturnType(closure);
|
||||
check(closure, problemsHolder, expectedClosureType != null && expectedClosureType != PsiType.VOID);
|
||||
check(closure, problemsHolder, ReturnStatus.getReturnStatus(closure));
|
||||
}
|
||||
|
||||
public void visitMethod(GrMethod method) {
|
||||
@@ -80,72 +97,70 @@ public class MissingReturnInspection extends GroovySuppressableInspectionTool {
|
||||
|
||||
final GrOpenBlock block = method.getBlock();
|
||||
if (block != null) {
|
||||
final boolean mustReturnValue = method.getReturnTypeElementGroovy() != null && method.getReturnType() != PsiType.VOID;
|
||||
check(block, problemsHolder, mustReturnValue);
|
||||
check(block, problemsHolder, ReturnStatus.getReturnStatus(method));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private static void check(GrCodeBlock block, ProblemsHolder holder, boolean mustReturnValue) {
|
||||
if (methodMissesSomeReturns(block, mustReturnValue)) {
|
||||
private static void check(GrCodeBlock block, ProblemsHolder holder, ReturnStatus returnStatus) {
|
||||
if (methodMissesSomeReturns(block, returnStatus)) {
|
||||
addNoReturnMessage(block, holder);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean methodMissesSomeReturns(GrControlFlowOwner block, boolean mustReturnValue) {
|
||||
if (!mustReturnValue) {
|
||||
public static boolean methodMissesSomeReturns(GrControlFlowOwner block, ReturnStatus returnStatus) {
|
||||
if (returnStatus == ReturnStatus.shouldNotReturnValue) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final Ref<Boolean> always = new Ref<Boolean>(true);
|
||||
final Ref<Boolean> alwaysHaveReturn = new Ref<Boolean>(true);
|
||||
final Ref<Boolean> sometimesHaveReturn = new Ref<Boolean>(false);
|
||||
final Ref<Boolean> hasExplicitReturn = new Ref<Boolean>(false);
|
||||
final Ref<Boolean> sometimes = new Ref<Boolean>(false);
|
||||
ControlFlowUtils.visitAllExitPoints(block, new ControlFlowUtils.ExitPointVisitor() {
|
||||
@Override
|
||||
public boolean visitExitPoint(Instruction instruction, @Nullable GrExpression returnValue) {
|
||||
if (instruction instanceof MaybeReturnInstruction) {
|
||||
if (((MaybeReturnInstruction)instruction).mayReturnValue()) {
|
||||
sometimes.set(true);
|
||||
sometimesHaveReturn.set(true);
|
||||
}
|
||||
else {
|
||||
always.set(false);
|
||||
alwaysHaveReturn.set(false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
final PsiElement element = instruction.getElement();
|
||||
if (element instanceof GrReturnStatement) {
|
||||
sometimes.set(true);
|
||||
sometimesHaveReturn.set(true);
|
||||
if (returnValue != null) {
|
||||
hasExplicitReturn.set(true);
|
||||
}
|
||||
}
|
||||
else if (instruction instanceof ThrowingInstruction) {
|
||||
sometimes.set(true);
|
||||
sometimesHaveReturn.set(true);
|
||||
}
|
||||
else if (element instanceof GrAssertStatement) {
|
||||
sometimes.set(true);
|
||||
sometimesHaveReturn.set(true);
|
||||
int count = 0;
|
||||
for (Instruction _i : instruction.allSuccessors()) {
|
||||
count++;
|
||||
}
|
||||
if (count <= 1) {
|
||||
always.set(false);
|
||||
alwaysHaveReturn.set(false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
always.set(false);
|
||||
alwaysHaveReturn.set(false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
if (!sometimes.get()) {
|
||||
if (returnStatus == ReturnStatus.mustReturnValue && !sometimesHaveReturn.get()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return sometimes.get() && !always.get();
|
||||
return sometimesHaveReturn.get() && !alwaysHaveReturn.get();
|
||||
}
|
||||
|
||||
private static void addNoReturnMessage(GrCodeBlock block, ProblemsHolder holder) {
|
||||
|
||||
@@ -43,6 +43,7 @@ public class GroovyCodeStyleSettings extends CustomCodeStyleSettings {
|
||||
|
||||
public boolean SPACE_IN_NAMED_ARGUMENT = true;
|
||||
public boolean ALIGN_MULTILINE_LIST_OR_MAP = false;
|
||||
public boolean SPACE_WITHIN_LIST_OR_MAP = false;
|
||||
|
||||
public GroovyCodeStyleSettings(CodeStyleSettings container) {
|
||||
super("GroovyCodeStyleSettings", container);
|
||||
|
||||
+1
@@ -115,6 +115,7 @@ public class GroovyLanguageCodeStyleSettingsProvider extends LanguageCodeStyleSe
|
||||
"SPACE_WITHIN_ANNOTATION_PARENTHESES"
|
||||
);
|
||||
consumer.showCustomOption(GroovyCodeStyleSettings.class, "SPACE_IN_NAMED_ARGUMENT", "In named argument after ':'", CodeStyleSettingsCustomizable.SPACES_OTHER);
|
||||
consumer.showCustomOption(GroovyCodeStyleSettings.class, "SPACE_WITHIN_LIST_OR_MAP", "List and maps literals", CodeStyleSettingsCustomizable.SPACES_WITHIN);
|
||||
return;
|
||||
}
|
||||
consumer.showAllStandardOptions();
|
||||
|
||||
+1
-1
@@ -546,7 +546,7 @@ public class GroovySpacingProcessor extends GroovyElementVisitor {
|
||||
@Override
|
||||
public void visitListOrMap(GrListOrMap listOrMap) {
|
||||
if (myType1 == mLBRACK || myType2 == mRBRACK) {
|
||||
createSpaceInCode(mySettings.SPACE_WITHIN_BRACKETS);
|
||||
createSpaceInCode(myGroovySettings.SPACE_WITHIN_LIST_OR_MAP);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+17
-6
@@ -24,10 +24,7 @@ import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.FoldingGroup;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiAnonymousClass;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.tree.LeafPsiElement;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.util.containers.hash.HashSet;
|
||||
@@ -215,6 +212,7 @@ public class GroovyFoldingBuilder extends CustomFoldingBuilder implements Groovy
|
||||
return text.contains("\n") || text.contains("\r") || text.contains("\r\n");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected String getLanguagePlaceholderText(@NotNull ASTNode node, @NotNull TextRange range) {
|
||||
final IElementType elemType = node.getElementType();
|
||||
@@ -245,8 +243,21 @@ public class GroovyFoldingBuilder extends CustomFoldingBuilder implements Groovy
|
||||
return settings.isCollapseImports();
|
||||
}
|
||||
|
||||
if (node.getElementType() == GROOVY_DOC_COMMENT) {
|
||||
return settings.isCollapseJavadocs();
|
||||
if (node.getElementType() == GROOVY_DOC_COMMENT || node.getElementType() == mML_COMMENT) {
|
||||
PsiElement element = node.getPsi();
|
||||
PsiElement parent = element.getParent();
|
||||
if (parent instanceof GroovyFile) {
|
||||
PsiElement firstChild = parent.getFirstChild();
|
||||
if (firstChild instanceof PsiWhiteSpace) {
|
||||
firstChild = firstChild.getNextSibling();
|
||||
}
|
||||
if (element.equals(firstChild)) {
|
||||
return settings.isCollapseFileHeader();
|
||||
}
|
||||
}
|
||||
if (node.getElementType() == GROOVY_DOC_COMMENT) {
|
||||
return settings.isCollapseJavadocs();
|
||||
}
|
||||
}
|
||||
|
||||
if ((node.getElementType() == OPEN_BLOCK || node.getElementType() == CONSTRUCTOR_BODY) && node.getTreeParent().getElementType() == METHOD_DEFINITION) {
|
||||
|
||||
+1
-1
@@ -247,7 +247,7 @@ public class ClassItemGeneratorImpl implements ClassItemGenerator {
|
||||
ExpressionContext extended = context.extend();
|
||||
extended.searchForLocalVarsToWrap((GroovyPsiElement)scriptFile);
|
||||
new CodeBlockGenerator(builder, extended, exitPoints)
|
||||
.visitStatementOwner((GroovyFile)scriptFile, MissingReturnInspection.methodMissesSomeReturns((GroovyFile)scriptFile, true));
|
||||
.visitStatementOwner((GroovyFile)scriptFile, MissingReturnInspection.methodMissesSomeReturns((GroovyFile)scriptFile, MissingReturnInspection.ReturnStatus.mustReturnValue));
|
||||
builder.append("\n}\n");
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -87,7 +87,7 @@ public class ClosureGenerator {
|
||||
|
||||
Collection<GrStatement> myExitPoints = ControlFlowUtils.collectReturns(block);
|
||||
boolean shouldInsertReturnNull =
|
||||
!(returnType instanceof PsiPrimitiveType) && MissingReturnInspection.methodMissesSomeReturns(block, false);
|
||||
!(returnType instanceof PsiPrimitiveType) && MissingReturnInspection.methodMissesSomeReturns(block, MissingReturnInspection.ReturnStatus.shouldNotReturnValue);
|
||||
|
||||
new CodeBlockGenerator(builder, context.extend(), myExitPoints).generateCodeBlock(block, shouldInsertReturnNull);
|
||||
builder.append('\n');
|
||||
|
||||
+2
-1
@@ -101,7 +101,8 @@ public class CodeBlockGenerator extends Generator {
|
||||
if (!method.isConstructor() && returnType != PsiType.VOID) {
|
||||
myExitPoints.addAll(ControlFlowUtils.collectReturns(block));
|
||||
shouldInsertReturnNull = !(returnType instanceof PsiPrimitiveType) &&
|
||||
MissingReturnInspection.methodMissesSomeReturns(block, method.getReturnTypeElementGroovy() != null);
|
||||
MissingReturnInspection.methodMissesSomeReturns(block,
|
||||
MissingReturnInspection.ReturnStatus.getReturnStatus(method));
|
||||
}
|
||||
|
||||
if (block != null) {
|
||||
|
||||
@@ -41,6 +41,7 @@ public class MissingReturnTest extends LightCodeInsightFixtureTestCase {
|
||||
public void testImplicitReturnNull() throws Throwable {doTest();}
|
||||
public void testMissingReturnInClosure() {doTest();}
|
||||
public void testFinally() {doTest();}
|
||||
public void testClosureWithExplicitExpectedType() {doTest()}
|
||||
|
||||
private void doTest() {
|
||||
myFixture.enableInspections(new MissingReturnInspection());
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
def foo(Closure<String> c) {
|
||||
return c().substring(1)
|
||||
}
|
||||
|
||||
foo {
|
||||
print 2
|
||||
<warning descr="Not all execution paths return a value">}</warning>
|
||||
|
||||
foo {
|
||||
's'
|
||||
}
|
||||
|
||||
foo {
|
||||
if (a) 's'
|
||||
<warning descr="Not all execution paths return a value">}</warning>
|
||||
|
||||
foo {
|
||||
if (a) 'a' else 'b'
|
||||
}
|
||||
+2
-2
@@ -2,7 +2,7 @@ def mkString(def i) {}
|
||||
|
||||
print([1, 2, 3].collect {
|
||||
mkString(it)
|
||||
<warning descr="Not all execution paths return a value">}</warning>)
|
||||
})
|
||||
|
||||
|
||||
print([1, 2, 3].collect {
|
||||
@@ -10,5 +10,5 @@ print([1, 2, 3].collect {
|
||||
})
|
||||
|
||||
Closure c1 = { mkString(it)}
|
||||
Closure<Integer> c2 = {mkString(it)<warning descr="Not all execution paths return a value">}</warning>
|
||||
Closure<Integer> c2 = {mkString(it); if (a) return 2<warning descr="Not all execution paths return a value">}</warning>
|
||||
def c3 = {mkString(it)}
|
||||
Reference in New Issue
Block a user