Merge remote branch 'origin/master'

This commit is contained in:
irengrig
2012-03-28 16:58:44 +04:00
14 changed files with 254 additions and 60 deletions
@@ -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> {
@@ -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;
}
@@ -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);
@@ -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();
@@ -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);
}
}
@@ -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) {
@@ -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");
}
@@ -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');
@@ -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());
@@ -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,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)}