diff --git a/platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontOptions.java b/platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontOptions.java index 6beb28ed4419..c65a3d9a45fd 100644 --- a/platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontOptions.java +++ b/platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontOptions.java @@ -845,14 +845,15 @@ public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract private String myName; private boolean myIsNew = false; - private MyColorScheme(EditorColorsScheme parenScheme) { - super(parenScheme, DefaultColorSchemesManager.getInstance()); - myFontSize = parenScheme.getEditorFontSize(); - myLineSpacing = parenScheme.getLineSpacing(); - myFontName = parenScheme.getEditorFontName(); - myName = parenScheme.getName(); - if (parenScheme instanceof ExternalizableScheme) { - getExternalInfo().copy(((ExternalizableScheme)parenScheme).getExternalInfo()); + private MyColorScheme(EditorColorsScheme parentScheme) { + super(parentScheme, DefaultColorSchemesManager.getInstance()); + myFontSize = parentScheme.getEditorFontSize(); + myLineSpacing = parentScheme.getLineSpacing(); + myFontName = parentScheme.getEditorFontName(); + setQuickDocFontSize(parentScheme.getQuickDocFontSize()); + myName = parentScheme.getName(); + if (parentScheme instanceof ExternalizableScheme) { + getExternalInfo().copy(((ExternalizableScheme)parentScheme).getExternalInfo()); } initFonts(); } @@ -897,6 +898,7 @@ public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract if (myFontSize != myParentScheme.getEditorFontSize()) return true; if (myLineSpacing != myParentScheme.getLineSpacing()) return true; if (!myFontName.equals(myParentScheme.getEditorFontName())) return true; + if (myQuickDocFontSize != myParentScheme.getQuickDocFontSize()) return true; return false; } @@ -908,6 +910,7 @@ public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract scheme.setEditorFontSize(myFontSize); scheme.setEditorFontName(myFontName); scheme.setLineSpacing(myLineSpacing); + scheme.setQuickDocFontSize(getQuickDocFontSize()); for (EditorSchemeAttributeDescriptor descriptor : myDescriptors) { descriptor.apply(scheme); diff --git a/platform/lang-impl/src/com/intellij/application/options/colors/FontOptions.java b/platform/lang-impl/src/com/intellij/application/options/colors/FontOptions.java index b5af79290948..43ba211fd2f0 100644 --- a/platform/lang-impl/src/com/intellij/application/options/colors/FontOptions.java +++ b/platform/lang-impl/src/com/intellij/application/options/colors/FontOptions.java @@ -20,6 +20,7 @@ import com.intellij.application.options.SelectFontDialog; import com.intellij.openapi.application.ApplicationBundle; import com.intellij.openapi.editor.colors.EditorColorsScheme; import com.intellij.openapi.editor.ex.EditorSettingsExternalizable; +import com.intellij.openapi.options.FontSize; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.ui.FixedSizeButton; @@ -34,13 +35,18 @@ import javax.swing.event.DocumentEvent; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.util.*; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; public class FontOptions extends JPanel implements OptionsPanel{ private final ColorAndFontOptions myOptions; private JTextField myEditorFontSizeField; + private JComboBox myEditorJavaDocFontSizeBox; private JTextField myLineSpacingField; private JTextField myFontNameField; @@ -67,18 +73,14 @@ public class FontOptions extends JPanel implements OptionsPanel{ myLineSpacingField.setText(Float.toString(getCurrentScheme().getLineSpacing())); myEditorFontSizeField.setText(Integer.toString(getCurrentScheme().getEditorFontSize())); + myEditorJavaDocFontSizeBox.setSelectedItem(getCurrentScheme().getQuickDocFontSize()); myFontNameField.setText(getCurrentScheme().getEditorFontName()); - if (ColorAndFontOptions.isReadOnly(myOptions.getSelectedScheme())) { - myLineSpacingField.setEnabled(false); - myEditorFontSizeField.setEditable(false); - myFontNameField.setEnabled(false); - } - else { - myLineSpacingField.setEnabled(true); - myEditorFontSizeField.setEditable(true); - myFontNameField.setEnabled(true); - } + boolean enabled = !ColorAndFontOptions.isReadOnly(myOptions.getSelectedScheme()); + myLineSpacingField.setEnabled(enabled); + myEditorFontSizeField.setEditable(enabled); + myFontNameField.setEnabled(enabled); + myEditorJavaDocFontSizeBox.setEnabled(enabled); myIsInSchemeChange = false; @@ -100,6 +102,13 @@ public class FontOptions extends JPanel implements OptionsPanel{ } private JPanel createFontPanel() { + JPanel result = new JPanel(new GridLayout(2, 1)); + result.add(createEditorFontPanel()); + result.add(createJavaDocFontPanel()); + return result; + } + + private JPanel createEditorFontPanel() { JPanel editorFontPanel = new JPanel(); editorFontPanel.setBorder(IdeBorderFactory.createTitledBorder(ApplicationBundle.message("group.editor.font"))); editorFontPanel.setLayout(new GridBagLayout()); @@ -202,6 +211,31 @@ public class FontOptions extends JPanel implements OptionsPanel{ return editorFontPanel; } + + private JPanel createJavaDocFontPanel() { + JPanel result = new JPanel(new FlowLayout(FlowLayout.LEFT)); + result.setBorder(IdeBorderFactory.createTitledBorder(ApplicationBundle.message("group.quickdoc.font"))); + result.add(new JLabel(ApplicationBundle.message("editbox.font.size"))); + myEditorJavaDocFontSizeBox = new JComboBox(FontSize.values()); + result.add(myEditorJavaDocFontSizeBox); + + myEditorJavaDocFontSizeBox.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + if (myIsInSchemeChange) { + return; + } + Object item = e.getItem(); + if (e.getStateChange() != ItemEvent.SELECTED || !(item instanceof FontSize)) { + return; + } + getCurrentScheme().setQuickDocFontSize((FontSize)item); + updateDescription(true); + } + }); + + return result; + } private void selectFont() { initFontTables(); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java index 96acbd3ec591..a76ea0da0af5 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java @@ -27,6 +27,11 @@ import com.intellij.lang.documentation.DocumentationProvider; import com.intellij.lang.documentation.ExternalDocumentationHandler; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.editor.colors.EditorColorsManager; +import com.intellij.openapi.editor.colors.EditorColorsScheme; +import com.intellij.openapi.editor.ex.EditorSettingsExternalizable; +import com.intellij.openapi.editor.ex.util.EditorUtil; +import com.intellij.openapi.options.FontSize; import com.intellij.openapi.ui.popup.JBPopup; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.IconLoader; @@ -35,7 +40,6 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.SmartPointerManager; import com.intellij.psi.SmartPsiElementPointer; import com.intellij.ui.IdeBorderFactory; -import com.intellij.ui.ScrollPaneFactory; import com.intellij.ui.SideBorder; import com.intellij.ui.components.JBScrollPane; import com.intellij.util.Consumer; @@ -46,7 +50,7 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.event.HyperlinkEvent; import javax.swing.event.HyperlinkListener; -import javax.swing.text.View; +import javax.swing.text.*; import java.awt.*; import java.awt.event.*; import java.util.List; @@ -67,6 +71,7 @@ public class DocumentationComponent extends JPanel implements Disposable { private boolean myIsEmpty; private boolean myIsShown; private final JLabel myElementLabel; + private Style myFontSizeStyle; private static class Context { final SmartPsiElementPointer element; @@ -146,7 +151,36 @@ public class DocumentationComponent extends JPanel implements Disposable { myEditorPane.setEditable(false); myEditorPane.setBackground(HintUtil.INFORMATION_COLOR); myEditorPane.setEditorKit(UIUtil.getHTMLEditorKit()); - myScrollPane = ScrollPaneFactory.createScrollPane(myEditorPane); + myScrollPane = new JBScrollPane(myEditorPane) { + @Override + protected void processMouseWheelEvent(MouseWheelEvent e) { + if (!EditorSettingsExternalizable.getInstance().isWheelFontChangeEnabled() || !EditorUtil.isChangeFontSize(e)) { + super.processMouseWheelEvent(e); + return; + } + + int change = Math.abs(e.getWheelRotation()); + boolean increase = e.getWheelRotation() <= 0; + EditorColorsManager colorsManager = EditorColorsManager.getInstance(); + EditorColorsScheme scheme = colorsManager.getGlobalScheme(); + FontSize newFontSize = scheme.getQuickDocFontSize(); + for (; change > 0; change--) { + if (increase) { + newFontSize = newFontSize.larger(); + } + else { + newFontSize = newFontSize.smaller(); + } + } + + if (newFontSize == scheme.getQuickDocFontSize()) { + return; + } + + scheme.setQuickDocFontSize(newFontSize); + applyFontSize(); + } + }; myScrollPane.setBorder(null); final MouseAdapter mouseAdapter = new MouseAdapter() { @@ -332,12 +366,14 @@ public class DocumentationComponent extends JPanel implements Disposable { if (!myIsShown && myHint != null) { myEditorPane.setText(text); + applyFontSize(); myManager.showHint(myHint); myIsShown = justShown = true; } if (!justShown) { myEditorPane.setText(text); + applyFontSize(); } if (!skip) { @@ -351,6 +387,23 @@ public class DocumentationComponent extends JPanel implements Disposable { }); } + private void applyFontSize() { + Document document = myEditorPane.getDocument(); + if (!(document instanceof StyledDocument)) { + return; + } + + StyledDocument styledDocument = (StyledDocument)document; + if (myFontSizeStyle == null) { + myFontSizeStyle = styledDocument.addStyle("active", null); + } + + EditorColorsManager colorsManager = EditorColorsManager.getInstance(); + EditorColorsScheme scheme = colorsManager.getGlobalScheme(); + StyleConstants.setFontSize(myFontSizeStyle, scheme.getQuickDocFontSize().getSize()); + styledDocument.setCharacterAttributes(0, document.getLength(), myFontSizeStyle, true); + } + private void goBack() { if (myBackStack.isEmpty()) return; Context context = myBackStack.pop(); diff --git a/platform/platform-api/src/com/intellij/openapi/editor/colors/EditorColorsScheme.java b/platform/platform-api/src/com/intellij/openapi/editor/colors/EditorColorsScheme.java index f1577314dade..379056243569 100644 --- a/platform/platform-api/src/com/intellij/openapi/editor/colors/EditorColorsScheme.java +++ b/platform/platform-api/src/com/intellij/openapi/editor/colors/EditorColorsScheme.java @@ -16,9 +16,11 @@ package com.intellij.openapi.editor.colors; import com.intellij.openapi.editor.markup.TextAttributes; +import com.intellij.openapi.options.FontSize; import com.intellij.openapi.options.Scheme; import com.intellij.openapi.util.JDOMExternalizable; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; import java.awt.*; @@ -39,6 +41,9 @@ public interface EditorColorsScheme extends Cloneable, JDOMExternalizable, Schem int getEditorFontSize(); void setEditorFontSize(int fontSize); + FontSize getQuickDocFontSize(); + void setQuickDocFontSize(@NotNull FontSize fontSize); + String getEditorFontName(); void setEditorFontName(String fontName); diff --git a/platform/platform-api/src/com/intellij/openapi/options/FontSize.java b/platform/platform-api/src/com/intellij/openapi/options/FontSize.java new file mode 100644 index 000000000000..1963791c5adf --- /dev/null +++ b/platform/platform-api/src/com/intellij/openapi/options/FontSize.java @@ -0,0 +1,76 @@ +/* + * 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.openapi.options; + +import com.intellij.openapi.application.ApplicationBundle; +import com.intellij.openapi.util.text.StringUtil; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import javax.swing.text.html.StyleSheet; + +/** + * Enumerates common font size values (inspired by CSS 'font-size' property values). + *

+ * Note that such elements selection (and this enum existence at all) is based on the fact that standard Swing {@link JEditorPane} + * used by IJ for providing quick doc works only with predefined set of font sizes (see {@link StyleSheet#sizeMapDefault}). + * + * @author Denis Zhdanov + * @since 1/26/11 10:22 AM + */ +public enum FontSize { + + XX_SMALL(8), X_SMALL(10), SMALL(12), MEDIUM(14), LARGE(18), X_LARGE(24), XX_LARGE(36); + + private final String myName; + private final int mySize; + + FontSize(int size) { + myName = ApplicationBundle.message("font.size." + StringUtil.toLowerCase(name().replace("_", ""))); + mySize = size; + } + + public int getSize() { + return mySize; + } + + /** + * @return {@link FontSize} that is one unit large than the current one; current object if it already stands for a maximum size + */ + @NotNull + public FontSize larger() { + int i = ordinal(); + return i >= values().length - 1 ? this : values()[i + 1]; + } + + /** + * @return {@link FontSize} that is one unit smaller than the current one; current object if it already stands for a minimum size + */ + @NotNull + public FontSize smaller() { + int i = ordinal(); + return i > 0 ? values()[i - 1] : this; + } + + public String getEnumName() { + return super.toString(); + } + + @Override + public String toString() { + return myName; + } +} diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/colors/impl/AbstractColorsScheme.java b/platform/platform-impl/src/com/intellij/openapi/editor/colors/impl/AbstractColorsScheme.java index 25bde40ea7aa..8f347c825d37 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/colors/impl/AbstractColorsScheme.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/colors/impl/AbstractColorsScheme.java @@ -24,6 +24,7 @@ import com.intellij.openapi.editor.colors.*; import com.intellij.openapi.editor.colors.ex.DefaultColorSchemesManager; import com.intellij.openapi.editor.markup.EffectType; import com.intellij.openapi.editor.markup.TextAttributes; +import com.intellij.openapi.options.FontSize; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.WriteExternalException; @@ -32,15 +33,20 @@ import com.intellij.util.containers.HashMap; import gnu.trove.THashMap; import org.jdom.Element; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; import java.awt.*; import java.util.*; import java.util.List; public abstract class AbstractColorsScheme implements EditorColorsScheme { + + private static final FontSize DEFAULT_FONT_SIZE = FontSize.SMALL; + protected EditorColorsScheme myParentScheme; protected int myEditorFontSize; + protected FontSize myQuickDocFontSize = DEFAULT_FONT_SIZE; protected float myLineSpacing; private final Map myFonts = new EnumMap(EditorFontType.class); @@ -71,6 +77,7 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme { @NonNls private static final String BACKGROUND_COLOR_NAME = "BACKGROUND"; @NonNls private static final String LINE_SPACING = "LINE_SPACING"; @NonNls private static final String EDITOR_FONT_SIZE = "EDITOR_FONT_SIZE"; + @NonNls private static final String EDITOR_QUICK_JAVADOC_FONT_SIZE = "EDITOR_QUICK_DOC_FONT_SIZE"; protected AbstractColorsScheme(EditorColorsScheme parentScheme, DefaultColorSchemesManager defaultColorSchemesManager) { myParentScheme = parentScheme; @@ -109,6 +116,7 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme { newScheme.myEditorFontSize = myEditorFontSize; newScheme.myLineSpacing = myLineSpacing; newScheme.setEditorFontName(getEditorFontName()); + newScheme.myQuickDocFontSize = myQuickDocFontSize; final Set types = myFonts.keySet(); for (EditorFontType type : types) { @@ -130,6 +138,11 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme { myEditorFontSize = fontSize; initFonts(); } + + @Override + public void setQuickDocFontSize(@NotNull FontSize fontSize) { + myQuickDocFontSize = fontSize; + } public void setLineSpacing(float lineSpacing) { myLineSpacing = lineSpacing; @@ -154,6 +167,12 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme { return myEditorFontSize; } + @NotNull + @Override + public FontSize getQuickDocFontSize() { + return myQuickDocFontSize; + } + public float getLineSpacing() { return myLineSpacing <= 0 ? 1.0f : myLineSpacing; } @@ -307,6 +326,9 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme { else if (EDITOR_FONT_SIZE.equals(name)) { myEditorFontSize = Integer.parseInt(value); } + else if (EDITOR_QUICK_JAVADOC_FONT_SIZE.equals(name)) { + myQuickDocFontSize = FontSize.valueOf(value); + } else if (AbstractColorsScheme.EDITOR_FONT_NAME.equals(name)) { setEditorFontName(value); } @@ -330,6 +352,13 @@ public abstract class AbstractColorsScheme implements EditorColorsScheme { element.setAttribute(VALUE_ELEMENT, String.valueOf(getEditorFontSize())); parentNode.addContent(element); + if (DEFAULT_FONT_SIZE != getQuickDocFontSize()) { + element = new Element(OPTION_ELEMENT); + element.setAttribute(NAME_ATTR, EDITOR_QUICK_JAVADOC_FONT_SIZE); + element.setAttribute(VALUE_ELEMENT, getQuickDocFontSize().getEnumName()); + parentNode.addContent(element); + } + element = new Element(OPTION_ELEMENT); element.setAttribute(NAME_ATTR, EDITOR_FONT_NAME); element.setAttribute(VALUE_ELEMENT, getEditorFontName()); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/colors/impl/DelegateColorScheme.java b/platform/platform-impl/src/com/intellij/openapi/editor/colors/impl/DelegateColorScheme.java index f5e6dfc1f0ce..8475188e09af 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/colors/impl/DelegateColorScheme.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/colors/impl/DelegateColorScheme.java @@ -20,6 +20,7 @@ import com.intellij.openapi.editor.colors.EditorColorsScheme; import com.intellij.openapi.editor.colors.EditorFontType; import com.intellij.openapi.editor.colors.TextAttributesKey; import com.intellij.openapi.editor.markup.TextAttributes; +import com.intellij.openapi.options.FontSize; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.WriteExternalException; import org.jdom.Element; @@ -87,6 +88,16 @@ public abstract class DelegateColorScheme implements EditorColorsScheme { myDelegate.setEditorFontSize(fontSize); } + @Override + public FontSize getQuickDocFontSize() { + return myDelegate.getQuickDocFontSize(); + } + + @Override + public void setQuickDocFontSize(@NotNull FontSize fontSize) { + myDelegate.setQuickDocFontSize(fontSize); + } + @Override public String getEditorFontName() { return myDelegate.getEditorFontName(); 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 26c9c2c6b443..070e853c27b8 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 @@ -24,10 +24,12 @@ import com.intellij.openapi.editor.impl.ComplementaryFontsRegistry; import com.intellij.openapi.editor.impl.FontInfo; import com.intellij.openapi.editor.impl.IterationState; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NotNull; import java.awt.*; +import java.awt.event.MouseWheelEvent; import java.util.List; public class EditorUtil { @@ -576,6 +578,12 @@ public class EditorUtil { editor.getSelectionModel().removeSelection(); editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); } + + public static boolean isChangeFontSize(MouseWheelEvent e) { + return SystemInfo.isMac + ? !e.isControlDown() && e.isMetaDown() && !e.isAltDown() && !e.isShiftDown() + : e.isControlDown() && !e.isMetaDown() && !e.isAltDown() && !e.isShiftDown(); + } } 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 3887e3583e17..af207585d4a5 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 @@ -55,6 +55,7 @@ import com.intellij.openapi.editor.impl.softwrap.SoftWrapHelper; import com.intellij.openapi.editor.markup.*; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileEditor.ex.IdeDocumentHistory; +import com.intellij.openapi.options.FontSize; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Queryable; @@ -4973,6 +4974,16 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi initFonts(); } + @Override + public FontSize getQuickDocFontSize() { + return myGlobalScheme.getQuickDocFontSize(); + } + + @Override + public void setQuickDocFontSize(@NotNull FontSize fontSize) { + myGlobalScheme.setQuickDocFontSize(fontSize); + } + public String getEditorFontName() { if (myFaceName == null) { return getGlobal().getEditorFontName(); @@ -5520,12 +5531,6 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi info.put("caret", visual.getLine() + ":" + visual.getColumn()); } - public static boolean isChangeFontSize(MouseWheelEvent e) { - return SystemInfo.isMac - ? !e.isControlDown() && e.isMetaDown() && !e.isAltDown() && !e.isShiftDown() - : e.isControlDown() && !e.isMetaDown() && !e.isAltDown() && !e.isShiftDown(); - } - private class MyScrollPane extends JBScrollPane { @@ -5535,7 +5540,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi protected void processMouseWheelEvent(MouseWheelEvent e) { if (mySettings.isWheelFontChangeEnabled()) { - if (isChangeFontSize(e)) { + if (EditorUtil.isChangeFontSize(e)) { setFontSize(myScheme.getEditorFontSize() - e.getWheelRotation()); return; } diff --git a/platform/platform-resources-en/src/messages/ApplicationBundle.properties b/platform/platform-resources-en/src/messages/ApplicationBundle.properties index fcdb403e126b..d359268ed914 100644 --- a/platform/platform-resources-en/src/messages/ApplicationBundle.properties +++ b/platform/platform-resources-en/src/messages/ApplicationBundle.properties @@ -477,6 +477,14 @@ title.colors.and.fonts=Colors \\& Fonts progress.analysing.font=Analysing font: {0} button.edit.scopes=Edit Scopes... group.editor.font=Editor Font +group.quickdoc.font=QuickDoc Font +font.size.xxsmall=xx-small +font.size.xsmall=x-small +font.size.small=small +font.size.medium=medium +font.size.large=large +font.size.xlarge=x-large +font.size.xxlarge=xx-large label.font.name=Name: editbox.font.size=Size: editbox.line.spacing=Line spacing: 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 1d72e0b3f8a4..365a0c64bab4 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java @@ -20,6 +20,8 @@ import com.intellij.execution.configurations.RunProfile; import com.intellij.execution.executors.DefaultDebugExecutor; import com.intellij.execution.filters.HyperlinkInfo; import com.intellij.execution.filters.OpenFileHyperlinkInfo; +import com.intellij.execution.process.ProcessAdapter; +import com.intellij.execution.process.ProcessEvent; import com.intellij.execution.process.ProcessHandler; import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.execution.runners.ProgramRunner; @@ -190,6 +192,11 @@ public class XDebugSessionImpl implements XDebugSession { myDependentBreakpointListener = new MyDependentBreakpointListener(); dependentBreakpointManager.addListener(myDependentBreakpointListener); + myDebugProcess.getProcessHandler().addProcessListener(new ProcessAdapter() { + public void processTerminated(final ProcessEvent event) { + stopImpl(); + } + }); if (!myShowTabOnSuspend) { initSessionTab(); } @@ -562,7 +569,7 @@ public class XDebugSessionImpl implements XDebugSession { return myStopped; } - public void stopImpl() { + private void stopImpl() { if (myStopped) return; myDebugProcess.stop(); diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerManagerImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerManagerImpl.java index cc132d1a7ecc..ceb0cf688dfd 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerManagerImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerManagerImpl.java @@ -184,9 +184,11 @@ public class XDebuggerManagerImpl extends XDebuggerManager implements ProjectCom public void removeSession(@NotNull XDebugSessionImpl session) { XDebugSessionTab sessionTab = session.getSessionTab(); - XDebugSessionData data = sessionTab.saveData(); mySessions.remove(session); - mySessionData.put(session.getDebugProcess().getProcessHandler(), data); + if (sessionTab != null) { + XDebugSessionData data = sessionTab.saveData(); + mySessionData.put(session.getDebugProcess().getProcessHandler(), data); + } if (myActiveSession == session) { myActiveSession = null; onActiveSessionChanged(); 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 3adb2a26a7fb..ae440c5402c3 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 @@ -21,8 +21,6 @@ import com.intellij.execution.ExecutionResult; import com.intellij.execution.Executor; import com.intellij.execution.configurations.RunProfile; import com.intellij.execution.executors.DefaultDebugExecutor; -import com.intellij.execution.process.ProcessAdapter; -import com.intellij.execution.process.ProcessEvent; import com.intellij.execution.process.ProcessHandler; import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.execution.runners.ProgramRunner; @@ -35,7 +33,10 @@ import com.intellij.execution.ui.actions.CloseAction; import com.intellij.execution.ui.layout.PlaceInGrid; import com.intellij.ide.CommonActionsManager; import com.intellij.ide.actions.ContextHelpAction; -import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.actionSystem.ActionGroup; +import com.intellij.openapi.actionSystem.ActionManager; +import com.intellij.openapi.actionSystem.ActionPlaces; +import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; import com.intellij.ui.content.Content; @@ -44,7 +45,6 @@ import com.intellij.util.ArrayUtil; import com.intellij.xdebugger.XDebugProcess; import com.intellij.xdebugger.XDebugSession; import com.intellij.xdebugger.XDebuggerBundle; -import com.intellij.xdebugger.impl.XDebugSessionImpl; import com.intellij.xdebugger.impl.actions.XDebuggerActions; import com.intellij.xdebugger.impl.frame.XDebugViewBase; import com.intellij.xdebugger.impl.frame.XFramesView; @@ -145,11 +145,6 @@ public class XDebugSessionTab extends DebuggerSessionTabBase { private static ExecutionResult createExecutionResult(@NotNull final XDebugSession session) { final XDebugProcess debugProcess = session.getDebugProcess(); ProcessHandler processHandler = debugProcess.getProcessHandler(); - processHandler.addProcessListener(new ProcessAdapter() { - public void processTerminated(final ProcessEvent event) { - ((XDebugSessionImpl)session).stopImpl(); - } - }); return new DefaultExecutionResult(debugProcess.createConsole(), processHandler); } diff --git a/plugins/groovy/resources/inspectionDescriptions/GroovyAccessibility.html b/plugins/groovy/resources/inspectionDescriptions/GroovyAccessibility.html new file mode 100644 index 000000000000..4a1c9cc15c75 --- /dev/null +++ b/plugins/groovy/resources/inspectionDescriptions/GroovyAccessibility.html @@ -0,0 +1,6 @@ + + + +This inspection reports all references which exceed access rights. +
Powered by InspectorGroovy + \ No newline at end of file diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyBundle.properties b/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyBundle.properties index ce1156ed033a..7d372d9b73c1 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyBundle.properties +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyBundle.properties @@ -178,7 +178,7 @@ change.modifier=Make ''{0}'' {1} change.modifier.not=Make ''{0}'' not {1} change.modifier.family.name=Change modifiers # suppress inspection "UnusedProperty" -packageLocal.visibility.presentation=property +packageLocal.visibility.presentation=default visible # suppress inspection "UnusedProperty" protected.visibility.presentation=protected # suppress inspection "UnusedProperty" 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 258571806c4a..9704abc4cfb7 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java @@ -25,16 +25,16 @@ import com.intellij.lang.annotation.AnnotationHolder; import com.intellij.lang.annotation.Annotator; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.IndexNotReadyException; -import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.infos.CandidateInfo; import com.intellij.psi.search.searches.SuperMethodsSearch; -import com.intellij.psi.util.*; -import com.intellij.util.ArrayUtil; -import com.intellij.util.IncorrectOperationException; +import com.intellij.psi.util.InheritanceUtil; +import com.intellij.psi.util.MethodSignature; +import com.intellij.psi.util.MethodSignatureBackedByPsiMethod; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.containers.HashSet; import com.intellij.util.containers.MultiMap; import gnu.trove.THashSet; @@ -185,13 +185,13 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { if (resolved instanceof PsiMember) { highlightMemberResolved(myHolder, referenceExpression, ((PsiMember)resolved)); } - if (!resolveResult.isAccessible()) { + /*if (!resolveResult.isAccessible()) { String message = GroovyBundle.message("cannot.access", referenceExpression.getReferenceName()); final Annotation annotation = myHolder.createWarningAnnotation(getElementToHighlight(referenceExpression), message); if (resolved instanceof PsiMember) { registerAccessFix(annotation, referenceExpression, ((PsiMember)resolved)); } - } + }*/ //todo uncomment when correct isStatic() is working if (!resolveResult.isStaticsOK() && resolved instanceof PsiModifierListOwner) { @@ -252,6 +252,7 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { } } + /* private static void registerAccessFix(Annotation annotation, PsiElement place, PsiMember refElement) { if (refElement instanceof PsiCompiledElement) return; PsiModifierList modifierList = refElement.getModifierList(); @@ -284,6 +285,7 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { LOG.error(e); } } + */ private static void registerStaticImportFix(GrReferenceExpression referenceExpression, Annotation annotation) { final String referenceName = referenceExpression.getReferenceName(); @@ -580,7 +582,7 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { checkDefaultMapConstructor(myHolder, argList, constructor); } - if (!constructorResolveResult.isAccessible()) { +/* if (!constructorResolveResult.isAccessible()) { String message = GroovyBundle.message("cannot.access", PsiFormatUtil.formatMethod((PsiMethod)constructor, PsiSubstitutor.EMPTY, PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_TYPE | @@ -590,7 +592,7 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { )); final Annotation annotation = myHolder.createWarningAnnotation(getElementToHighlight(refElement), message); registerAccessFix(annotation, refElement, ((PsiMember)constructor)); - } + }*/ } else { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/GroovyFix.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/GroovyFix.java index 49ea83d4bf0a..1309857a4275 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/GroovyFix.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/GroovyFix.java @@ -35,6 +35,8 @@ import org.jetbrains.plugins.groovy.lang.psi.api.util.GrStatementOwner; public abstract class GroovyFix implements LocalQuickFix { + public static final GroovyFix[] EMPTY_ARRAY = new GroovyFix[0]; + //to appear in "Apply Fix" statement when multiple Quick Fixes exist @NotNull public String getFamilyName() { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/GroovyInspectionBundle.properties b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/GroovyInspectionBundle.properties index 6fa06f83eb3a..8f08a7f701cf 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/GroovyInspectionBundle.properties +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/GroovyInspectionBundle.properties @@ -59,3 +59,7 @@ pointless.boolean.quickfix=Simplify Cannot.perform.undo.operation=Cannot perform undo operation Undo.disable=Undo disabled field.already.defined=Variables with field names + +access.to.inaccessible.element=Access to inaccessible element + +cannot.reference.nonstatic=Cannot reference nonstatic symbol ''{0}'' from static context \ No newline at end of file diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/GroovyInspectionProvider.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/GroovyInspectionProvider.java index e89d519e06bc..cf7199c1f789 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/GroovyInspectionProvider.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/GroovyInspectionProvider.java @@ -135,6 +135,7 @@ public class GroovyInspectionProvider implements InspectionToolProvider, Applica GroovyInfiniteRecursionInspection.class, GroovyDivideByZeroInspection.class, GroovyResultOfObjectAllocationIgnoredInspection.class, + GroovyAccessibilityInspection.class, GroovyClassNamingConventionInspection.class, GroovyInterfaceNamingConventionInspection.class, diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/bugs/GroovyAccessibilityInspection.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/bugs/GroovyAccessibilityInspection.java new file mode 100644 index 000000000000..a1d885d4a0dc --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/bugs/GroovyAccessibilityInspection.java @@ -0,0 +1,253 @@ +/* + * 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.codeInspection.bugs; + +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiFormatUtil; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.ArrayUtil; +import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.groovy.GroovyBundle; +import org.jetbrains.plugins.groovy.codeInspection.BaseInspection; +import org.jetbrains.plugins.groovy.codeInspection.BaseInspectionVisitor; +import org.jetbrains.plugins.groovy.codeInspection.GroovyFix; +import org.jetbrains.plugins.groovy.codeInspection.GroovyInspectionBundle; +import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement; +import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; +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.expressions.GrConstructorCall; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrNewExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Maxim.Medvedev + */ +public class GroovyAccessibilityInspection extends BaseInspection { + private static final Logger LOG = Logger.getInstance("org.jetbrains.plugins.groovy.codeInspection.bugs.GroovyAccessibilityInspection"); + + @Override + protected BaseInspectionVisitor buildVisitor() { + return new MyVisitor(); + } + + @Nls + @NotNull + @Override + public String getGroupDisplayName() { + return PROBABLE_BUGS; + } + + @Nls + @NotNull + @Override + public String getDisplayName() { + return GroovyInspectionBundle.message("access.to.inaccessible.element"); + } + + @Override + protected String buildErrorString(Object... args) { + return GroovyBundle.message("cannot.access", args); + } + + @Override + protected GroovyFix[] buildFixes(PsiElement location) { + if (!(location instanceof GrReferenceElement || location instanceof GrConstructorCall)) { + location = location.getParent(); + } + + final GroovyResolveResult resolveResult; + if (location instanceof GrConstructorCall) { + resolveResult = ((GrConstructorCall)location).advancedResolve(); + } + else { + resolveResult = ((GrReferenceElement)location).advancedResolve(); + } + + final PsiElement element = resolveResult.getElement(); + if (!(element instanceof PsiMember)) return GroovyFix.EMPTY_ARRAY; + final PsiMember refElement = (PsiMember)element; + + if (refElement instanceof PsiCompiledElement) return GroovyFix.EMPTY_ARRAY; + + PsiModifierList modifierList = refElement.getModifierList(); + if (modifierList == null) return GroovyFix.EMPTY_ARRAY; + + List fixes = new ArrayList(); + try { + Project project = refElement.getProject(); + JavaPsiFacade facade = JavaPsiFacade.getInstance(project); + PsiModifierList modifierListCopy = facade.getElementFactory().createFieldFromText("int a;", null).getModifierList(); + modifierListCopy.setModifierProperty(PsiModifier.STATIC, modifierList.hasModifierProperty(PsiModifier.STATIC)); + @Modifier String minModifier = PsiModifier.PROTECTED; + if (refElement.hasModifierProperty(PsiModifier.PROTECTED)) { + minModifier = PsiModifier.PUBLIC; + } + String[] modifiers = {PsiModifier.PROTECTED, PsiModifier.PUBLIC, PsiModifier.PACKAGE_LOCAL}; + PsiClass accessObjectClass = PsiTreeUtil.getParentOfType(location, PsiClass.class, false); + if (accessObjectClass == null) { + accessObjectClass = ((GroovyFile)location.getContainingFile()).getScriptClass(); + } + for (int i = ArrayUtil.indexOf(modifiers, minModifier); i < modifiers.length; i++) { + String modifier = modifiers[i]; + modifierListCopy.setModifierProperty(modifier, true); + if (facade.getResolveHelper().isAccessible(refElement, modifierListCopy, location, accessObjectClass, null)) { + fixes.add(new GrModifierFix(refElement, refElement.getModifierList(), modifier, true)); + } + } + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + return fixes.toArray(new GroovyFix[fixes.size()]); + } + + private static class GrModifierFix extends GroovyFix { + private PsiMember myMember; + private PsiModifierList myModifierList; + private String myModifier; + private boolean myDoSet; + + public GrModifierFix(@NotNull PsiMember member, + @NotNull PsiModifierList modifierList, + String modifier, + boolean doSet) { + myMember = member; + myModifierList = modifierList; + myModifier = modifier; + myDoSet = doSet; + } + + @Override + protected void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException { + myModifierList.setModifierProperty(myModifier, myDoSet); + } + + @NotNull + @Override + public String getName() { + String name; + final PsiClass containingClass = myMember.getContainingClass(); + String containingClassName; + if (containingClass != null) { + containingClassName = containingClass.getName() + "."; + } + else { + containingClassName = ""; + } + + name = containingClassName + myMember.getName(); + + String modifierText = toPresentableText(myModifier); + + if (myDoSet) { + return GroovyBundle.message("change.modifier", name, modifierText); + } + else { + return GroovyBundle.message("change.modifier.not", name, modifierText); + } + } + } + + private static String toPresentableText(String modifier) { + return GroovyBundle.message(modifier + ".visibility.presentation"); + } + + @Override + public boolean isEnabledByDefault() { + return true; + } + + private static class MyVisitor extends BaseInspectionVisitor { + @Override + public void visitCodeReferenceElement(GrCodeReferenceElement refElement) { + super.visitCodeReferenceElement(refElement); + checkRef(refElement); + } + + @Override + public void visitReferenceExpression(GrReferenceExpression ref) { + super.visitReferenceExpression(ref); + checkRef(ref); + } + + @Override + public void visitNewExpression(GrNewExpression newExpression) { + checkConstructorCall(newExpression); + } + + private void checkConstructorCall(GrConstructorCall call) { + final GroovyResolveResult result = call.advancedResolve(); + if (result.getElement() == null) return; + final PsiElement constructor = result.getElement(); + if (!(constructor instanceof PsiMethod)) return; + if (!result.isAccessible()) { + + PsiElement refElement = null; + if (call instanceof GrNewExpression) { + refElement = ((GrNewExpression)call).getReferenceElement(); + } + else if (call instanceof GrConstructorInvocation) { + refElement = ((GrConstructorInvocation)call).getThisOrSuperKeyword(); + } + if (refElement == null) { + refElement = call; + } + + + registerError(refElement, + PsiFormatUtil.formatMethod((PsiMethod)constructor, PsiSubstitutor.EMPTY, + PsiFormatUtil.SHOW_NAME | + PsiFormatUtil.SHOW_TYPE | + PsiFormatUtil.TYPE_AFTER | + PsiFormatUtil.SHOW_PARAMETERS, + PsiFormatUtil.SHOW_TYPE + )); + } + } + + @Override + public void visitConstructorInvocation(GrConstructorInvocation invocation) { + super.visitConstructorInvocation(invocation); + checkConstructorCall(invocation); + } + + private void checkRef(GrReferenceElement ref) { + final GroovyResolveResult result = ref.advancedResolve(); + if (result == null) return; + if (result.getElement() == null) return; + if (!result.isAccessible()) { + registerError(getErrorLocation(ref), ref.getReferenceName()); + } + } + + @NotNull + private static PsiElement getErrorLocation(GrReferenceElement ref) { + final PsiElement nameElement = ref.getReferenceNameElement(); + if (nameElement != null) return nameElement; + return ref; + } + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java index 268e8fc0d27d..c20426953418 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java @@ -48,6 +48,7 @@ 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.blocks.GrClosableBlock; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAccessorMethod; @@ -432,7 +433,12 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl implements PsiClass containingClass = method.getContainingClass(); if (containingClass != null && CommonClassNames.JAVA_LANG_OBJECT.equals(containingClass.getQualifiedName()) && "getClass".equals(method.getName())) { - result = getTypeForObjectGetClass(facade, method); + if (seemsToBeQualifiedClassName(getQualifierExpression())) { + result = createJavaLangClassType(facade, facade.getElementFactory().createTypeFromText(getQualifier().getText(), this)); + } + else { + result = getTypeForObjectGetClass(facade, method); + } } else { result = PsiUtil.getSmartReturnType(method); } @@ -454,7 +460,12 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl implements else if (resolved == null) { GrExpression qualifier = getQualifierExpression(); if ("class".equals(getReferenceName())) { - result = createJavaLangClassType(JavaPsiFacade.getInstance(getProject()), getQualifierType()); + if (seemsToBeQualifiedClassName(qualifier)) { + assert qualifier != null; + result = createJavaLangClassType(facade, facade.getElementFactory().createTypeFromText(qualifier.getText(), this)); + } else { + result = createJavaLangClassType(facade, getQualifierType()); + } } else { if (qualifier != null) { @@ -487,6 +498,15 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl implements } } + private static boolean seemsToBeQualifiedClassName(@Nullable GrExpression qualifier) { + if (qualifier == null) return false; + while (qualifier instanceof GrReferenceExpression) { + if (((GrReferenceExpression)qualifier).getReferenceNameElement() instanceof GrLiteral) return false; + qualifier = ((GrReferenceExpression)qualifier).getQualifierExpression(); + } + return qualifier == null; + } + @Nullable private PsiType createJavaLangClassType(JavaPsiFacade facade, @Nullable PsiType type) { PsiType result = null; 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 e2693ef2ab23..5f7ffd506860 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.java @@ -20,6 +20,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.codeInspection.GroovyImportsTracker; import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyAssignabilityCheckInspection; import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyUncheckedAssignmentOfMemberOfRawTypeInspection; +import org.jetbrains.plugins.groovy.codeInspection.bugs.GroovyAccessibilityInspection; import org.jetbrains.plugins.groovy.codeInspection.bugs.GroovyResultOfObjectAllocationIgnoredInspection; import org.jetbrains.plugins.groovy.codeInspection.control.GroovyTrivialConditionalInspection; import org.jetbrains.plugins.groovy.codeInspection.control.GroovyTrivialIfInspection; @@ -262,12 +263,16 @@ public class GroovyHighlightingTest extends LightCodeInsightFixtureTestCase { public void testTupleTypeAssignments() throws Exception{doTest(new GroovyAssignabilityCheckInspection());} public void testUnusedImportsForImportsOnDemand() throws Exception { - doTest(); + doTest(new GroovyAccessibilityInspection()); final Set unusedImportStatements = GroovyImportsTracker.getInstance(getProject()).getUnusedImportStatements(((GroovyFile)myFixture.getFile())); assertEquals(0, unusedImportStatements.size()); } + public void testInaccessibleConstructorCall() { + doTest(new GroovyAccessibilityInspection()); + } + public void testSignatureIsNotApplicableToList() throws Exception { doTest(new GroovyAssignabilityCheckInspection()); } diff --git a/plugins/groovy/testdata/highlighting/InaccessibleConstructorCall.groovy b/plugins/groovy/testdata/highlighting/InaccessibleConstructorCall.groovy new file mode 100644 index 000000000000..ab047c55d7d5 --- /dev/null +++ b/plugins/groovy/testdata/highlighting/InaccessibleConstructorCall.groovy @@ -0,0 +1,9 @@ +class Base { + private Base(int i){} +} + +class Extension extends Base { + def Extension() { + super(1) + } +} \ No newline at end of file